FDrS?5#CF)r z;lI9laS+6hiS;!d#9zn&E4v{~FO(M=QXt~1$S_>raJhLlhsW8N?fiVfMlz5r1Fg}j z>)mv22F#MKE9UL|V`3xfT72Viu)VU@K1ex_quFiJ!o*Z6N;i_lalV(LlucK;TwDDH zl#zk}L)IwLkBK*jKO%-rO{cHE?19{0b}RId2$Wyl{6)mzX<09cy@Ef5+N%{L&UYr} z&;z&TvUl)OFU`D`_vF^^&6=bs8YeMg&+|g!T{Xcb>;Va?_vDm1kUWb zva!$R!(KqdA-x~c>U#kiCuCZpakl`&$$+|LQ|l=XXo{h!G|k81H#E}$SR1kWs$TxN zif~Lr7EU^%3Vl`p#y{wiEttMYMC 6M{)(QHGju#n1`t|(-3@2013Cs7o$vh`RGWW$<->LVeBMq05?=9~ zr>`GTMffFP0t#UZe|1owEbEL)QBgfl@eFl=lhTp&GAl%+>3|H$pUm_$CpfeiE$91a zdcLsciurr)XY T!g7y#|Md{W~#EFH(TFa?DpkuqKjjJb`l0fvDhomP8_bE-A4w;D%T$AnSg{RQO zAk%)mf!h^%t<6U9puBt(Yu59G>xCgL35wC&XCSz->^{Q>M6Uy4b>(N*jtii&0MZ{3 z%fgW?i!UsX4bs=lrbjd7sf^aSJ>jwR?r50lb)^A?KX4zwgs!jupzxR1ia?;B_X=gn z3l4qiyT@Y<<|E+PtVg&wftaSa Pa*uI)w=8G;hqU-()Pd6%5R8fX3OfZ)$gduvY;| zFMiICuI_7^8ZQQfOA+vF2%`JwRGneE!nDZMfwFp$1qI1B44^^igo=5*(olJlws-Ds z5cUZ`=pfGe>7+rG9e9Z`a3LZL%6 smPz;*=l zE?}?)jCmUa2p^dEMg`0(+q-Kozx0jo|FyRlu{Y26|3#5tXWk|1dH?_b07*qoM6N<$ Ef>x1+k^lez literal 0 HcmV?d00001 diff --git a/static/tabbar/di_icon_sy.png b/static/tabbar/di_icon_sy.png new file mode 100644 index 0000000000000000000000000000000000000000..2ff2917dd803ef5da5b2afb7145f6838f95a0f81 GIT binary patch literal 1008 zcmV Px&s!2paR9Hvtm`Q9DM-+zt*E5EAhyZaxScFp!2q_M94?*F`F%lsxk`;CX(>1bB zKym; Lt5+mMu(y$|&lIO$B z6)L!4iSIz10ce6RGl(*dDSrUKVJsjN@XvqUTU(fu?_i)|DkuWZ)eI&Y|J--%<#gev z4Zh;UuDaMzO*aEc6&M1tZoIJW`tJ6A6@4kqw7^%K5J_!_y8)^T2EqL<@mIZOYfrGa z|J4 y~IBpaX>3ijp&4GSHYy%X5{)R{~CkEizy}Jh=&jBCy}6M;u{)AGB!$fg93H zfanw$n}Q-vsVAHV^A1PYc~xI!@cPz0i)*}CHvnDLJfJRD(A;%>skVnIaZ2EZG*
~L(_eNq2WBKj8m-kUJkS_#a|Kjj|R9Uxtrodnu8;^6Y| zJ+1|Fj8@HnN5k* &^d(%ZyZ z^01c4J(f$g-7%#2w;I76A?F&>TuPw59^-P6 *L^W4@27HPZy9+|!+b0fl zJ%FWw+i`rrfWOD1toTirV(DJ<_}C5SCtGeet&Xv40r;fC1w;o 0qKzD!8M|_6*`WfXTcVK&?JC;n!HF7krgc&UMz_;D ziCJlpGvK8v$}<%&x!IyQRjQ@p4*)DyX|z$zdjNmr2sw^v(tA89MZ5p~TUFqUlTKQW zW10j$^0|2}$UkAE6=yur+&7=~G &+{J~L$I!FTKYQx0000 Px&l}SWFR9Hvtm``X_M;yn$ze%= J~ zi}nyvD^%*CExnc^CQWEX&}c;P<}svsGrO!I)Qgw4ruE{#)coK1m60{L$!_+&-S nM`KBUh=xZ zv)OEGp->njA{7RPh%^y(d!9EFMqf!&7kD H(8Qd7t z%gloSw$&JXo{0LTl$UB*9~qpPDVNKgvDTg{Q-o0&T%n$oQhpV+Xd{7ZtzC #D*KdDb76f$gHKFMw53w1F=lp$OYDP)vW<<6-RX4tuQ2AJz_r%z0k{g_tuUr_ zX#NJ!qm=rsnnzV|W6S|-?Rg? vpgi)V~ ziRhf?c_%9sZP|?H^ZD0SR#rxsxhHDGnDy6Esnn vxFgIy0wZhN#Jo zi1N(*ky7f97Y$0lCnqN}LWofSZ`KqgxkdM_wR?QuAAcTV6+8%nLqzlwfTrZ)*X6t@ zggEMX-mr5aW)@oOb3%wOT|w4mo$%sfp?>Rm-T)b6hMD fMDzuK8|B*JrUkFq4&B6N&iEGi1_gNsz-=M|Gw%k_UT5*nx;>s`#-|z@8b0sr z>|8zJT(Dd&mnjqqKLU8S#s^3aoQQ(v=H~Z1Iy(L>2RA)Ey?tR};TAJ@)c~Iu_!59! zN~yaWK^bFqGV?TmS0chE1J2B&U0q#!!@wA0t}yeSFxnS1$$$emu9W&d42;(L7=Z7> zXcGq~q9amDcgIq77-RaG`9f7;sUVq*7cX{(!oV0~4i_(y!pNU%w!llWwUzP8o9E@; zDt`iKi&8oN!&bSclqz9b_dXs3!377h$-sw{QYB35!1MWh+w$`AWR!ctgfsq+wbu82 z-|d9eQTAW`)YR15OG``NF!Kih-l&%SguovFxC!9I+RGrv^B-~(zDF%Isz?9;002ov JPDHLkV1nfX-0c7W literal 0 HcmV?d00001 diff --git a/static/tabbar/di_icon_wd.png b/static/tabbar/di_icon_wd.png new file mode 100644 index 0000000000000000000000000000000000000000..72ffc0108d55c603c70fe9982ea4c19da303a883 GIT binary patch literal 1017 zcmV Px&vq?ljR9Hvtm`!XHWf;f*&&*cPq#&&Ui+X@WJ}yFbq(mZ0PmmY|0_9@lqo(uj z7TXIa6ApU-ZyYSz-FF&_V7QbTK`(HjAOzCFY=8?v6FeXk2;U_tbax)JOG{8%=6R>v z-H^D~`9Ht^Z)SET@4SQ({O0azs;&;ImNTP)8TABA2k_c3`X&Q6h|o`j-a%{V@Ws!& z2FF`V;{nuvv$;0^Qf>>FlK{OcWAR-OrR_(t9sOT?drLO+Y$~$&A}{%2o`Zb^yb-0G zfh#sypPqKp$D+(f5`VW-t>geb0Af)}pPI>$g|%mz^+8jPv3R^A>5v`#0^k+XvN7_1 za^CtN+miN8c&6gyXmtv}Vv`a 5N!>S#K(K|JQ+s1XxnINsfVF z%AC4MM;lT($(&gHopfS)mBrU3(5RWAfM%ReW^PF4#o~+GTc_kEJ-R1>M$NW=@;JR|OS>PrCI%l6j@I|~9c^VY2L zzIr `ASRBRM=~G zw7LnPwgkBHAsDv`;)O5w@opEFPx^6Ft{^VnAuYGv^ZNc5FZbPeF&|D8A5Qlpz}ms! nw=2E=4!di`^*QJ_AlUK`baE>7!S$Pr00000NkvXXu0mjf)q(CM literal 0 HcmV?d00001 diff --git a/static/tabbar/di_icon_wdh.png b/static/tabbar/di_icon_wdh.png new file mode 100644 index 0000000000000000000000000000000000000000..155b276d7d548d3af9fc0c9f1a08371e7ada3f29 GIT binary patch literal 987 zcmV<110?*3P) Px&l}SWFR9Hvtm`i9>R~X0t-^mQp1g($~v9^l_gk%+S&&ec;+PYF`td?pvqNqCs z-DFj8F^k%riz?{OisB}u^pQ>7_@-uV&b>6NM1*nSBN!BXkd!jh^OY+TNo(SK=Vmfd zaJKjV_}z2w9KLf2HTaE>k1wB|p5E%5+rrE_B5DEfQ6>5@GfxsxsFb?W*w}cft*!0F zLThOu0fj=LIh)P)JLe7oSSieUs+2lYDwR%jcXvM#dR~*I29M+Tb7sEC%xlt=6VU@A z+7kr9wN(Bzrje169Yiz;Ad|*F%Ts3NU0q#Wzxw8QuXq$inwhTyX!I?cM?XzOo3+-F zPo5VzGgA~rw*YkelnAs1t@U~$VuALh#0xx%qV3H5n>5@ Xfv#UBfIwmE4G5GNC@QO?(^Gp(&R#PsQKkVu0c`osb!3PEg8d_Uh zOTIgi1frthVzHR*>+AbR;t_) ! zI|2Oc2_%(&ZH)OvD)s`;=kuz!xA!W5P0|91j)-my4Gn#f&*z;)pJ=?mEARPgBD&1X zZPJn|y4wJ@7-J@U^1Q)k-~rqO(CSk*hqee{qc61gibqkjiJ1=q_y)l81wzl*lVjXZ zM08ebeM6clTJbOpHz=jPOCG5-IHm52bM9C!m;0ld|Bc{dV`I%zQ&VS%Xjd|eR|~7f z^<*Yz=E0_>rbF%R?em^V=Y >^Hs)$Vh`Id?FZ%l$r=a87V*?O_0?04&NR zSdDnr^<;ZIVvITcf6r^+*4l50=y<(ejcPYhInEu^T7N%V`ycQqiuN<}kJZAK;yMu> z&|06H>3#(shT%G;RPt~BU@5=^oqshnG;HYX?ELf9K5nhe6459#w+jN6OhQCs%-ms& zDZO0rIF64v=T0sekw>vo>Sz!Ir>Js3xC=l$3w!h|hV)*sSo|#cz_XQ^=iDn7qqP>9 zM6`|KIR3#oceECP^~z96og`~*0YI)^r8Vja6Y$3XnrjqTub3wZcye-I=;z{k0nhZ5 z6L9et(t6XqsqZ~_y`RQA{pb7=zzG0r--7wO+Jj5x^E&|g{{`2)JmystxIzE`002ov JPDHLkV1j_?-(3Iz literal 0 HcmV?d00001 diff --git a/static/tabbar/di_icon_zr.png b/static/tabbar/di_icon_zr.png new file mode 100644 index 0000000000000000000000000000000000000000..ccd65b879bc604bceffb6be39d4ced1ea583e31b GIT binary patch literal 1125 zcmV-r1e*JaP) Px(A4x<(R9Hvtm|biXRTRhnXWA{aB}nAKP|+Bl{78V#jQEil ^d7UE;l;ciAaT}Tiv6ej?2GCaZ9wiMM zOBs1A&RnsA8+q{th;snV@?{25&avcM062~b!~*{CJKI|;?W08o(l>%4;7DquZPTe8 z`^KWeM+Waaw7H{cA~nE(sRBbl$!)HzKJ#Mlpo+epCK7n(Az^A0JOEHfFbE!WiJv}e z6;20>`&S(rT+fR%0Ywm6LnUX7F|etel}EzFhXE(U7CA8Qp1TNxBCx+uyB%S_8FbMG z0ym`92BO1YtPP5ILp|Xbm^V7Y9#!>K247a#vNYv24FJ$p%>(Mn70q3JF4OayN}Lk7 zA*}}i`V_zt71IcsA%NF7!v40AM?-Mk&OS%XJpkr6GK*>a3KMN9Tlo(foC$S?8D!eo zZU*lJ&~Sn=K~LE*f%cZH{Oh3FCv8ojWqs@0Q&-yh!B`VBP*A(iDy^f>pWDzsGCOb% zxFM}O8T2^;%Y$Y~NdG;+PdUQ=<$C`a;4AFRBTcM*0^qiUAi~=I;ga{vS*!5%l)*H( znHL*8f=$4@u 9|f z1UP^nE{(UCKfnCmxOp(!$r^tHphXdW*b#D}A+37|wB2KTQDZv{22Q|nm%O9oX$^nL zi1_5xwx-MME&_K40k69q`UAl$&K-`hhZF&(W%nJ}wxG4y9afCHR`FQD3G@=f>unin zZ&>l`6OS(#OA~YPrhzLajw*}4;!%kd;}Ze@35*j|=N4BB% 46&>J0^tOhUz^ Px&{z*hZR9Hvtm`!M0RTRhn=O*K{Y8ugn7^4dzptu-&@6A&JB5qs=S}TQM{U`-- zQv_YOsI^)!*o6xbT#2;WqEZz#R&XT|7a_^LZ;~N~ic77vBGk6Qjx(9uBezUKK4voa z&3n&PFANNG&-tI aPG z_9P|jVDDSyKCShYP~Bkgsi~>KLZL9u%zkmnd=OE&x3_m!sZ=@}A|3>8t-T+>R{(Ac z5lvz92Y}sL>*-D!9l_%`e%d+r0TFHMB$mZIGyf}ucwQ;>@s?{syGdV!*4i;5I+#Hb zCVeI*qN7sE*V+|r%Zyhll^Yt3#z|)0oit*`_FoqYg=b2o(mxw@H-TGg? =ohO|FDk1vkb#M?~)fDCQSG zm2yo8@q(1{gjXSE7S`IMLWoy AR-!7N_{pl zF|n<$ug?OwHv#;j5MtCh=h^xJT=W@#41oW (p^z`)n6}V;29-NsU9v&Y4At`vX zmxtadW)BYFOub%L{&s3^ZtnI*qj5T9qsGj4B{)^(0`B(??<%EU@>!4L_z*LPE-axh zDmQRPM2|=*zmMbiLBB$V5(V1j1KtdNUI_6PGw)^Q2LgdY&2j|~h3Lla8hAHZOXCxi z@!tRpriqe+@9$dcbxfP~ n4_kMkc1)2T Px(u}MThR9Hu?nBQ*{RTRh1cXqdkiNTtM(pp+IEogaE!;?=w`NSJWgIa4)nlc2V zrbJ1tm?C1Zqymj38siTVGba88zVfg>YTZ(n# !?UwD%F|+eyyEAv@&hE@S z&fI&>XTJA*&%HCCn6Bsf+f-?3`xiP>FF>ohg5ingH-3yMJRy!i24wNSM>JwSSQ9US zlM_$8^<^A6B7>TcO)f|)EE9on>hE2>BT-=^ftrvhjdhojZYto@e|Gkrjsn{-r~$ct zH=$7lQXYnhKhL%t8EO<(o ?AjPB`S?^lZ%!1(pu#|8)# zSmA-72IT$QC5=dLuqMS?xlIS)%2eyIqXhWE`huE}#R$d;v!K;60DU*ry8JF-SQpI{ zf>t1Jt!cVXP1 A)7;RA$b?+2Y>VNO#W>P$r%>?Q^!$z2>4hsL7?4YI%Nmif+~$nx zJRdDBvv^GstUavA?AtQE`2pqk>GmD3;+fgAqs)9FMtx!r1>gdn{`br>gC4Jm?k9}6 z_O~uUAf#Vg^K9ha{44038JPo9d!_%mmc-j+YwuLspygIqMmwIp FoT&0klE1iTg^Sa6WOcNLfj0E~BL-x#`ei3DQnF!mwvH1WKy%Myo$=*xG$3$a9 zSn}q;1}F4C<~oM{l%AeCrax1Oc+3nUkudauv^I{O;_m#O;apH@NI~1Dhg1+OP+67L z_uNjdrw{{ZZb$`;rP+FgZ436C;PKp~!~uFrB@d`fIY|w;i+Wo!CQzqFgLQ4(RH^QK zSJWEKeXKHDX7YR=yO!4Pxx@(|y*uA^Hkz5*a)T fdQ%061N0-+Y{)@<6q(z5&mC|Bb E^X+7MqWEIp(rtd+BNDT zaheVc(67Xx#Z7-uOVNaqj1Jl|^??cwUV0+R% T6)W zDmj8>7JDuVLDwH7f)xen4<9Y3?{$tZM>^)EC;J|w^7g-oxYO@ ud!=>Nqf62`v#SMmS=002ovPDHLkV1jlDVTb?# diff --git a/static/tabbar/sy_icon_syh.png b/static/tabbar/sy_icon_syh.png deleted file mode 100644 index b29f7c33baeb5dfcb320027877f5cecefb505781..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 706 zcmV;z0zLhSP) Px%d`Uz>R9Hvt*guHVP#g#F-#2Zwi=c3$;B=0K r#_asH>fH)+4ysv;9fxrNsVAnxsvUWa#wrd!P4vzxSsB z#q?N~l_R42M6^OgwxTE{P19b+6rK=Apk3rUB0BDkrzpxbP17F4(MM$HD5Q&H<{P@M z-;Iim1ocCDaJQtCx1(S~LnlDGzB^LNn_;n`pdpZ5AAoy8i0fgn6GOuyJvIAK*Y(v& zu@ga~B0acAQp&57U;{&AM7m|LCWN>W6dMQ{H`2uc*bqWo3WD{8P7CS5JrzP+1i<6K zW1%xZc5TeODW$wH4m%P$E2Jlj&&uWU`BJIW8J5|h&;*d~0(+rp+BpCN*a2u#NY4U$ z)oeD;6pO{SH?#jhlSaBQMNzg?RXq)$hwVY<1?kD`Tidpm4a4}|J${{^c|&@p{5=t! zl2Yzqj*+hS0}-7-tyX)?%$I|l4oS5Eu;yg+2NCU03K6j1ZJ4I{6~MuOFC@~8nZG$x zzrxJV-G!BiWPGO#;B0r**Xwn?-EJQRu($u6PN%a3;MkN0unypRe;>^JE0f85R8`ds za(i;FVe8X`0$3D6d CcT 7*?{AkvhfHOf(cYopSLl{y1vx^~jQ)QaHBIv*fGwXA2|e}B zSCL#Uw@@e)oWDdPAK&|ErBd0K&*wiA(V;PMqCnpWA(s8tiZ9d&P_0%EXS3NSM0A9i o_r$b4*#KVKw!LZ?#!o-!ANz$__e&cu6951J07*qoM6N<$g3ixNS^xk5 diff --git a/static/tabbar/sy_icon_wd.png b/static/tabbar/sy_icon_wd.png deleted file mode 100644 index 78ef662460ac562bcd38242bbba7ba7e8ab3555e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2066 zcmV+t2<`WYP) Px+%t=H+R9Hu)S!-+**A@Q0yT+K9LQ`yGuWc~+?M5gPjTC593R0q~KiVp7lhQ;{ z;0FYV2~R_krZK4?slkBlm>5ulQqfS6N>!`0Qc^`Ut R+Kb z5wjV% z1t3E50-?@aT=e8$t&>fP74q}k_zgKl$a)CUs11F*SPigWoI{RX03iaN3oPQMi+pNK z$0s1VlG Y)xY+M0*&(BM`|k z6T(7d`ope&a= |GZ Gl zFFJZ|-(vO935UIzG?f_H?dfr~zqja_pJoaOeY|?8V;`Ws<_GJ>&+4J}y9!Jatv!X? zp7TR&V5+0-Eg-hfW{!bnRkY2bs83e_k+Jwh v-Vo`A?Yf&oxIm> 0(Ll>n*BpGTsKGC-0e$@%I2c zWJL=3adtpG(p9kSbJMCrZ4H_xY2o6BpOul8S-YN8wSB?*9)r9p+S)84yIieAwuXY+ z%@C=Iw$+Ge-LrK+D+Z5S6!oDq84m}8bHT^r23cj~_;nG _N>pxMQuGt^O1#s#_7M5-8Q?h>HR!}YzFOLo;*6KXCo=DKB@CU)7)%Lk5#cOjl$ zgMCLQ &i+X^LiQ5p;3OuD#}{qp5lB z-4TKDc($tjv~X{~m9S!{HD9L2AJV7=FlXw|{fl25wvI229bOig(7MG~jKc-f%x?T# z_UWts?PwKDd?NAjuU%c%c*jptlu2U_2Xg)dkq7+X?HHC_J!Ct0xCEuQ wBYT!4RlJfj&ZflGkmD+`$ zORl`^$oji01HK*M@Q8h;8$U}g|JZ5KjGXTE)q7ede5P@LCE*|aKjlf!`Y{SR0o6$* z*8u)IF3=RP0ALxQ-7g}m0OXnr@f%T=Bx7;-MaO|Y^ZF87 u=17$EUs_zz#sx+=ZTCarlMQyiC!mx8lS{(6}d3c`)q~D`T`I0VSd5*9dtKz*ik} zX5eQqwBOUBRzV~uKs+B=KKD4-sQFdQ6(@}<7{2ooh?gJ;_$Z@bFtl$5i%!!BaZ{ {C(4$q6J^vKwyv9Z(8hpM4uA%Y9x|#*4pXoFkM+q(|!ja zahsw)&T=eZQJ>CZdn`7lQs0SIHvQI$$nV>Ge*kz3A}g$dGlheY7nNv_N2{C7gP}gB zsITEsQ2Uj6FY97i7WMAd?~SILUFUNmR^7bK`g(C_&$k)Z-UjJ?6FsxWpCd~ikCh+& zy%kp2xBCnPPrFUk`(G~Z-4%vNxx-t;pezj33>O|TJEDTV-482~cSR(7W?kI(QW{Pr zZbPYW#ww4PN0NmXx7?ePoztZoI28iPdq?6j3ww6HDUc0zVx_ocsOngU@jkDoA((}U zO9I@R$;H0Li4m&!mt&P}BL=>(cjs0SX?KP=)l0V-@1^QQEyd@t^Em6&x%*W?tD8 z^z3*CBH#0+gijC^&J9<$m^a;J{ZHrI8ebTN7{*8jYnED_ux)<#_H%^%ASGX&zFyms zyxaxyy0=v+1iB%TIJ=uWm!AS?RoeD#KtN5%y3v}JUISLp^IQi+Hc$W8cX$4BxVCkD zf-0|P;} )L;9OwRAFZ-dCQJ`FWH7^QWjw%xq)$?JLcTh#R03Mj?S zIOeS#t!etNX_GI7>K9~9Nr#B67fc36>rM@sigs=7o354a7Zdi&G{ 0=J&MVGcdaO1ucpO_Ov_4!kiQ^WRePyWp2 wqmw2iI}k63R-YO*6SsTI%F)_4I;|Z41Bj3XO7^& Px)w@E}nR9HvtnQLrRMHI)+nccpv1_To^8jAr672DlATS_I?l0b|f)ZhaVW5f?A zYSb7M{Xh&RzGLDeB4V^5L28PL!Jr8kQn8`5yE98_Ae4t`f+8w{(o&)AGJi9hz0GCQ zWq0pFW1{oz?mds+oO|xvbIvlQEv @@r-K-Ku~MFl!)dNQGl6u0N5y{9C2kjJ3GsYi;EB0FJ8W|zCf9I zmE$;Xy3UkR_A|SUh~{|#0PHR=FJD+wQ*+w=U2FY3fSl6BYs(iX5zUlR_Ig0yCZcCE zMCrT~QA$-4(f;v>=sCx6N|^ba2lRI$nw-J;2`S|yPl^Pz) xo{gO%qRTHSC^KVdXsE*bB5AGn0hpD+@c}8NecZ`q zU#OCjl0g7@RcL-9O2(L5>+9=xy3S*<*h9>`Va)T7`4Pu)THJflXtYTP@m)UAw6eZH ziReQq<>OvwsRMlt5tSqjGuu3T*>Rj#)8y6?(TZ^awGhEzaAs|7ZJ*a+JRYA6V4g81 zP+D5rF?;sx-@NyGdU~o7iNt;Y$<5@m{6^G9EH-iC#9OMWs?O%(u&=ML^yJBt-vfx` zBA+hf8#MKJ+Y^bzy>sTwIdLK9-QC?+27|%P0Bj%TYZU~V@_3Ay*93#Xjc$MAlB8Ok z2LZf9L|6MFOetLqP}jfx?(b&iWVr{xmUnXtEFnktb}>N<30PL$|3R~cC{Ka^PDGh` z&={kI5SoaN0QeJt5klCa<9Z^h17KgOiadjOo_HY<-OkLP0N5&}v<+g$)!yD-T3K0n z8#6xxpve!gAJARQyfS@=m8 E97NaQOo WncP0Nj)<5^48;Afmg9hij#j zPk5chVzE1!c@q)&nnW}6X(7boP$=|`*RIyO1;E1@Ha=uQ4-?T1V+j0QR8&;$t%zc= z*a9KMRsh9$MlxOeOdt@rJroL!wj>=L9TUpR%JyZbvVOE<$4_mprCSn0tO$q0>)hYt z@%R(~djU)+5HhLG%*UCzCL9hQckL;qYOL{Pb5RJ)}RcqY};C_#RkEN8O!`<%g?&*O*z)m+Z_3pm- z?RjjBnH7md4!8!i*6RQ~>RvPR=Z@nnNrLwF_EruK4z|00HZb!d$8o;&D8CQjNnbSC zmChUa#N+Whj4@kM>7gqsDw?aSs|QAh09{>Omj{DEo0InMn<-MtW1ieOn8R6_9cc^+ zJ56>RXS(NIm~4!(Bcj$sBJo&5LqmTOI$bv!jYjJ0>tkt(w(ZSpvXKWhDl03mnlWR> jAD$=ZIF4hhvC;Jpq3NK@Cz`6~00000NkvXXu0mjfdT!*h diff --git a/utils/qqmap-wx-jssdk.js b/utils/qqmap-wx-jssdk.js new file mode 100644 index 0000000..595b65b --- /dev/null +++ b/utils/qqmap-wx-jssdk.js @@ -0,0 +1,1122 @@ +/** + * 微信小程序JavaScriptSDK + * + * @version 1.2 + * @date 2019-03-06 + */ + +var ERROR_CONF = { + KEY_ERR: 311, + KEY_ERR_MSG: 'key格式错误', + PARAM_ERR: 310, + PARAM_ERR_MSG: '请求参数信息有误', + SYSTEM_ERR: 600, + SYSTEM_ERR_MSG: '系统错误', + WX_ERR_CODE: 1000, + WX_OK_CODE: 200 +}; +var BASE_URL = 'https://apis.map.qq.com/ws/'; +var URL_SEARCH = BASE_URL + 'place/v1/search'; +var URL_SUGGESTION = BASE_URL + 'place/v1/suggestion'; +var URL_GET_GEOCODER = BASE_URL + 'geocoder/v1/'; +var URL_CITY_LIST = BASE_URL + 'district/v1/list'; +var URL_AREA_LIST = BASE_URL + 'district/v1/getchildren'; +var URL_DISTANCE = BASE_URL + 'distance/v1/'; +var URL_DIRECTION = BASE_URL + 'direction/v1/'; +var MODE = { + driving: 'driving', + transit: 'transit' +}; +var EARTH_RADIUS = 6378136.49; +var Utils = { + /** + * md5加密方法 + * 版权所有©2011 Sebastian Tschan,https://blueimp.net + */ + safeAdd(x, y) { + var lsw = (x & 0xffff) + (y & 0xffff); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); + }, + bitRotateLeft(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + }, + md5cmn(q, a, b, x, s, t) { + return this.safeAdd(this.bitRotateLeft(this.safeAdd(this.safeAdd(a, q), this.safeAdd(x, t)), s), b); + }, + md5ff(a, b, c, d, x, s, t) { + return this.md5cmn((b & c) | (~b & d), a, b, x, s, t); + }, + md5gg(a, b, c, d, x, s, t) { + return this.md5cmn((b & d) | (c & ~d), a, b, x, s, t); + }, + md5hh(a, b, c, d, x, s, t) { + return this.md5cmn(b ^ c ^ d, a, b, x, s, t); + }, + md5ii(a, b, c, d, x, s, t) { + return this.md5cmn(c ^ (b | ~d), a, b, x, s, t); + }, + binlMD5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << (len % 32); + x[((len + 64) >>> 9 << 4) + 14] = len; + + var i; + var olda; + var oldb; + var oldc; + var oldd; + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for (i = 0; i < x.length; i += 16) { + olda = a; + oldb = b; + oldc = c; + oldd = d; + + a = this.md5ff(a, b, c, d, x[i], 7, -680876936); + d = this.md5ff(d, a, b, c, x[i + 1], 12, -389564586); + c = this.md5ff(c, d, a, b, x[i + 2], 17, 606105819); + b = this.md5ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = this.md5ff(a, b, c, d, x[i + 4], 7, -176418897); + d = this.md5ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = this.md5ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = this.md5ff(b, c, d, a, x[i + 7], 22, -45705983); + a = this.md5ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = this.md5ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = this.md5ff(c, d, a, b, x[i + 10], 17, -42063); + b = this.md5ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = this.md5ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = this.md5ff(d, a, b, c, x[i + 13], 12, -40341101); + c = this.md5ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = this.md5ff(b, c, d, a, x[i + 15], 22, 1236535329); + + a = this.md5gg(a, b, c, d, x[i + 1], 5, -165796510); + d = this.md5gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = this.md5gg(c, d, a, b, x[i + 11], 14, 643717713); + b = this.md5gg(b, c, d, a, x[i], 20, -373897302); + a = this.md5gg(a, b, c, d, x[i + 5], 5, -701558691); + d = this.md5gg(d, a, b, c, x[i + 10], 9, 38016083); + c = this.md5gg(c, d, a, b, x[i + 15], 14, -660478335); + b = this.md5gg(b, c, d, a, x[i + 4], 20, -405537848); + a = this.md5gg(a, b, c, d, x[i + 9], 5, 568446438); + d = this.md5gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = this.md5gg(c, d, a, b, x[i + 3], 14, -187363961); + b = this.md5gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = this.md5gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = this.md5gg(d, a, b, c, x[i + 2], 9, -51403784); + c = this.md5gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = this.md5gg(b, c, d, a, x[i + 12], 20, -1926607734); + + a = this.md5hh(a, b, c, d, x[i + 5], 4, -378558); + d = this.md5hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = this.md5hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = this.md5hh(b, c, d, a, x[i + 14], 23, -35309556); + a = this.md5hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = this.md5hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = this.md5hh(c, d, a, b, x[i + 7], 16, -155497632); + b = this.md5hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = this.md5hh(a, b, c, d, x[i + 13], 4, 681279174); + d = this.md5hh(d, a, b, c, x[i], 11, -358537222); + c = this.md5hh(c, d, a, b, x[i + 3], 16, -722521979); + b = this.md5hh(b, c, d, a, x[i + 6], 23, 76029189); + a = this.md5hh(a, b, c, d, x[i + 9], 4, -640364487); + d = this.md5hh(d, a, b, c, x[i + 12], 11, -421815835); + c = this.md5hh(c, d, a, b, x[i + 15], 16, 530742520); + b = this.md5hh(b, c, d, a, x[i + 2], 23, -995338651); + + a = this.md5ii(a, b, c, d, x[i], 6, -198630844); + d = this.md5ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = this.md5ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = this.md5ii(b, c, d, a, x[i + 5], 21, -57434055); + a = this.md5ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = this.md5ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = this.md5ii(c, d, a, b, x[i + 10], 15, -1051523); + b = this.md5ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = this.md5ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = this.md5ii(d, a, b, c, x[i + 15], 10, -30611744); + c = this.md5ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = this.md5ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = this.md5ii(a, b, c, d, x[i + 4], 6, -145523070); + d = this.md5ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = this.md5ii(c, d, a, b, x[i + 2], 15, 718787259); + b = this.md5ii(b, c, d, a, x[i + 9], 21, -343485551); + + a = this.safeAdd(a, olda); + b = this.safeAdd(b, oldb); + c = this.safeAdd(c, oldc); + d = this.safeAdd(d, oldd); + } + return [a, b, c, d]; + }, + binl2rstr(input) { + var i; + var output = ''; + var length32 = input.length * 32; + for (i = 0; i < length32; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff); + } + return output; + }, + rstr2binl(input) { + var i; + var output = []; + output[(input.length >> 2) - 1] = undefined; + for (i = 0; i < output.length; i += 1) { + output[i] = 0; + } + var length8 = input.length * 8; + for (i = 0; i < length8; i += 8) { + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32); + } + return output; + }, + rstrMD5(s) { + return this.binl2rstr(this.binlMD5(this.rstr2binl(s), s.length * 8)); + }, + rstrHMACMD5(key, data) { + var i; + var bkey = this.rstr2binl(key); + var ipad = []; + var opad = []; + var hash; + ipad[15] = opad[15] = undefined; + if (bkey.length > 16) { + bkey = this.binlMD5(bkey, key.length * 8); + } + for (i = 0; i < 16; i += 1) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5c5c5c5c; + } + hash = this.binlMD5(ipad.concat(this.rstr2binl(data)), 512 + data.length * 8); + return this.binl2rstr(this.binlMD5(opad.concat(hash), 512 + 128)); + }, + rstr2hex(input) { + var hexTab = '0123456789abcdef'; + var output = ''; + var x; + var i; + for (i = 0; i < input.length; i += 1) { + x = input.charCodeAt(i); + output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f); + } + return output; + }, + str2rstrUTF8(input) { + return unescape(encodeURIComponent(input)); + }, + rawMD5(s) { + return this.rstrMD5(this.str2rstrUTF8(s)); + }, + hexMD5(s) { + return this.rstr2hex(this.rawMD5(s)); + }, + rawHMACMD5(k, d) { + return this.rstrHMACMD5(this.str2rstrUTF8(k), str2rstrUTF8(d)); + }, + hexHMACMD5(k, d) { + return this.rstr2hex(this.rawHMACMD5(k, d)); + }, + + md5(string, key, raw) { + if (!key) { + if (!raw) { + return this.hexMD5(string); + } + return this.rawMD5(string); + } + if (!raw) { + return this.hexHMACMD5(key, string); + } + return this.rawHMACMD5(key, string); + }, + /** + * 得到md5加密后的sig参数 + * @param {Object} requestParam 接口参数 + * @param {String} sk签名字符串 + * @param {String} featrue 方法名 + * @return 返回加密后的sig参数 + */ + getSig(requestParam, sk, feature, mode) { + var sig = null; + var requestArr = []; + Object.keys(requestParam).sort().forEach(function(key){ + requestArr.push(key + '=' + requestParam[key]); + }); + if (feature == 'search') { + sig = '/ws/place/v1/search?' + requestArr.join('&') + sk; + } + if (feature == 'suggest') { + sig = '/ws/place/v1/suggestion?' + requestArr.join('&') + sk; + } + if (feature == 'reverseGeocoder') { + sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk; + } + if (feature == 'geocoder') { + sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk; + } + if (feature == 'getCityList') { + sig = '/ws/district/v1/list?' + requestArr.join('&') + sk; + } + if (feature == 'getDistrictByCityId') { + sig = '/ws/district/v1/getchildren?' + requestArr.join('&') + sk; + } + if (feature == 'calculateDistance') { + sig = '/ws/distance/v1/?' + requestArr.join('&') + sk; + } + if (feature == 'direction') { + sig = '/ws/direction/v1/' + mode + '?' + requestArr.join('&') + sk; + } + sig = this.md5(sig); + return sig; + }, + /** + * 得到终点query字符串 + * @param {Array|String} 检索数据 + */ + location2query(data) { + if (typeof data == 'string') { + return data; + } + var query = ''; + for (var i = 0; i < data.length; i++) { + var d = data[i]; + if (!!query) { + query += ';'; + } + if (d.location) { + query = query + d.location.lat + ',' + d.location.lng; + } + if (d.latitude && d.longitude) { + query = query + d.latitude + ',' + d.longitude; + } + } + return query; + }, + + /** + * 计算角度 + */ + rad(d) { + return d * Math.PI / 180.0; + }, + /** + * 处理终点location数组 + * @return 返回终点数组 + */ + getEndLocation(location){ + var to = location.split(';'); + var endLocation = []; + for (var i = 0; i < to.length; i++) { + endLocation.push({ + lat: parseFloat(to[i].split(',')[0]), + lng: parseFloat(to[i].split(',')[1]) + }) + } + return endLocation; + }, + + /** + * 计算两点间直线距离 + * @param a 表示纬度差 + * @param b 表示经度差 + * @return 返回的是距离,单位m + */ + getDistance(latFrom, lngFrom, latTo, lngTo) { + var radLatFrom = this.rad(latFrom); + var radLatTo = this.rad(latTo); + var a = radLatFrom - radLatTo; + var b = this.rad(lngFrom) - this.rad(lngTo); + var distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLatFrom) * Math.cos(radLatTo) * Math.pow(Math.sin(b / 2), 2))); + distance = distance * EARTH_RADIUS; + distance = Math.round(distance * 10000) / 10000; + return parseFloat(distance.toFixed(0)); + }, + /** + * 使用微信接口进行定位 + */ + getWXLocation(success, fail, complete) { + wx.getLocation({ + type: 'gcj02', + success: success, + fail: fail, + complete: complete + }); + }, + + /** + * 获取location参数 + */ + getLocationParam(location) { + if (typeof location == 'string') { + var locationArr = location.split(','); + if (locationArr.length === 2) { + location = { + latitude: location.split(',')[0], + longitude: location.split(',')[1] + }; + } else { + location = {}; + } + } + return location; + }, + + /** + * 回调函数默认处理 + */ + polyfillParam(param) { + param.success = param.success || function () { }; + param.fail = param.fail || function () { }; + param.complete = param.complete || function () { }; + }, + + /** + * 验证param对应的key值是否为空 + * + * @param {Object} param 接口参数 + * @param {String} key 对应参数的key + */ + checkParamKeyEmpty(param, key) { + if (!param[key]) { + var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + key +'参数格式有误'); + param.fail(errconf); + param.complete(errconf); + return true; + } + return false; + }, + + /** + * 验证参数中是否存在检索词keyword + * + * @param {Object} param 接口参数 + */ + checkKeyword(param){ + return !this.checkParamKeyEmpty(param, 'keyword'); + }, + + /** + * 验证location值 + * + * @param {Object} param 接口参数 + */ + checkLocation(param) { + var location = this.getLocationParam(param.location); + if (!location || !location.latitude || !location.longitude) { + var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + ' location参数格式有误'); + param.fail(errconf); + param.complete(errconf); + return false; + } + return true; + }, + + /** + * 构造错误数据结构 + * @param {Number} errCode 错误码 + * @param {Number} errMsg 错误描述 + */ + buildErrorConfig(errCode, errMsg) { + return { + status: errCode, + message: errMsg + }; + }, + + /** + * + * 数据处理函数 + * 根据传入参数不同处理不同数据 + * @param {String} feature 功能名称 + * search 地点搜索 + * suggest关键词提示 + * reverseGeocoder逆地址解析 + * geocoder地址解析 + * getCityList获取城市列表:父集 + * getDistrictByCityId获取区县列表:子集 + * calculateDistance距离计算 + * @param {Object} param 接口参数 + * @param {Object} data 数据 + */ + handleData(param,data,feature){ + if (feature == 'search') { + var searchResult = data.data; + var searchSimplify = []; + for (var i = 0; i < searchResult.length; i++) { + searchSimplify.push({ + id: searchResult[i].id || null, + title: searchResult[i].title || null, + latitude: searchResult[i].location && searchResult[i].location.lat || null, + longitude: searchResult[i].location && searchResult[i].location.lng || null, + address: searchResult[i].address || null, + category: searchResult[i].category || null, + tel: searchResult[i].tel || null, + adcode: searchResult[i].ad_info && searchResult[i].ad_info.adcode || null, + city: searchResult[i].ad_info && searchResult[i].ad_info.city || null, + district: searchResult[i].ad_info && searchResult[i].ad_info.district || null, + province: searchResult[i].ad_info && searchResult[i].ad_info.province || null + }) + } + param.success(data, { + searchResult: searchResult, + searchSimplify: searchSimplify + }) + } else if (feature == 'suggest') { + var suggestResult = data.data; + var suggestSimplify = []; + for (var i = 0; i < suggestResult.length; i++) { + suggestSimplify.push({ + adcode: suggestResult[i].adcode || null, + address: suggestResult[i].address || null, + category: suggestResult[i].category || null, + city: suggestResult[i].city || null, + district: suggestResult[i].district || null, + id: suggestResult[i].id || null, + latitude: suggestResult[i].location && suggestResult[i].location.lat || null, + longitude: suggestResult[i].location && suggestResult[i].location.lng || null, + province: suggestResult[i].province || null, + title: suggestResult[i].title || null, + type: suggestResult[i].type || null + }) + } + param.success(data, { + suggestResult: suggestResult, + suggestSimplify: suggestSimplify + }) + } else if (feature == 'reverseGeocoder') { + var reverseGeocoderResult = data.result; + var reverseGeocoderSimplify = { + address: reverseGeocoderResult.address || null, + latitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lat || null, + longitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lng || null, + adcode: reverseGeocoderResult.ad_info && reverseGeocoderResult.ad_info.adcode || null, + city: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.city || null, + district: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.district || null, + nation: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.nation || null, + province: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.province || null, + street: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street || null, + street_number: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street_number || null, + recommend: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.recommend || null, + rough: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.rough || null + }; + if (reverseGeocoderResult.pois) {//判断是否返回周边poi + var pois = reverseGeocoderResult.pois; + var poisSimplify = []; + for (var i = 0;i < pois.length;i++) { + poisSimplify.push({ + id: pois[i].id || null, + title: pois[i].title || null, + latitude: pois[i].location && pois[i].location.lat || null, + longitude: pois[i].location && pois[i].location.lng || null, + address: pois[i].address || null, + category: pois[i].category || null, + adcode: pois[i].ad_info && pois[i].ad_info.adcode || null, + city: pois[i].ad_info && pois[i].ad_info.city || null, + district: pois[i].ad_info && pois[i].ad_info.district || null, + province: pois[i].ad_info && pois[i].ad_info.province || null + }) + } + param.success(data,{ + reverseGeocoderResult: reverseGeocoderResult, + reverseGeocoderSimplify: reverseGeocoderSimplify, + pois: pois, + poisSimplify: poisSimplify + }) + } else { + param.success(data, { + reverseGeocoderResult: reverseGeocoderResult, + reverseGeocoderSimplify: reverseGeocoderSimplify + }) + } + } else if (feature == 'geocoder') { + var geocoderResult = data.result; + var geocoderSimplify = { + title: geocoderResult.title || null, + latitude: geocoderResult.location && geocoderResult.location.lat || null, + longitude: geocoderResult.location && geocoderResult.location.lng || null, + adcode: geocoderResult.ad_info && geocoderResult.ad_info.adcode || null, + province: geocoderResult.address_components && geocoderResult.address_components.province || null, + city: geocoderResult.address_components && geocoderResult.address_components.city || null, + district: geocoderResult.address_components && geocoderResult.address_components.district || null, + street: geocoderResult.address_components && geocoderResult.address_components.street || null, + street_number: geocoderResult.address_components && geocoderResult.address_components.street_number || null, + level: geocoderResult.level || null + }; + param.success(data,{ + geocoderResult: geocoderResult, + geocoderSimplify: geocoderSimplify + }); + } else if (feature == 'getCityList') { + var provinceResult = data.result[0]; + var cityResult = data.result[1]; + var districtResult = data.result[2]; + param.success(data,{ + provinceResult: provinceResult, + cityResult: cityResult, + districtResult: districtResult + }); + } else if (feature == 'getDistrictByCityId') { + var districtByCity = data.result[0]; + param.success(data, districtByCity); + } else if (feature == 'calculateDistance') { + var calculateDistanceResult = data.result.elements; + var distance = []; + for (var i = 0; i < calculateDistanceResult.length; i++){ + distance.push(calculateDistanceResult[i].distance); + } + param.success(data, { + calculateDistanceResult: calculateDistanceResult, + distance: distance + }); + } else if (feature == 'direction') { + var direction = data.result.routes; + param.success(data,direction); + } else { + param.success(data); + } + }, + + /** + * 构造微信请求参数,公共属性处理 + * + * @param {Object} param 接口参数 + * @param {Object} param 配置项 + * @param {String} feature 方法名 + */ + buildWxRequestConfig(param, options, feature) { + var that = this; + options.header = { "content-type": "application/json" }; + options.method = 'GET'; + options.success = function (res) { + var data = res.data; + if (data.status === 0) { + that.handleData(param, data, feature); + } else { + param.fail(data); + } + }; + options.fail = function (res) { + res.statusCode = ERROR_CONF.WX_ERR_CODE; + param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); + }; + options.complete = function (res) { + var statusCode = +res.statusCode; + switch(statusCode) { + case ERROR_CONF.WX_ERR_CODE: { + param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); + break; + } + case ERROR_CONF.WX_OK_CODE: { + var data = res.data; + if (data.status === 0) { + param.complete(data); + } else { + param.complete(that.buildErrorConfig(data.status, data.message)); + } + break; + } + default:{ + param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR, ERROR_CONF.SYSTEM_ERR_MSG)); + } + + } + }; + return options; + }, + + /** + * 处理用户参数是否传入坐标进行不同的处理 + */ + locationProcess(param, locationsuccess, locationfail, locationcomplete) { + var that = this; + locationfail = locationfail || function (res) { + res.statusCode = ERROR_CONF.WX_ERR_CODE; + param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); + }; + locationcomplete = locationcomplete || function (res) { + if (res.statusCode == ERROR_CONF.WX_ERR_CODE) { + param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); + } + }; + if (!param.location) { + that.getWXLocation(locationsuccess, locationfail, locationcomplete); + } else if (that.checkLocation(param)) { + var location = Utils.getLocationParam(param.location); + locationsuccess(location); + } + } +}; + + +class QQMapWX { + + /** + * 构造函数 + * + * @param {Object} options 接口参数,key 为必选参数 + */ + constructor(options) { + if (!options.key) { + throw Error('key值不能为空'); + } + this.key = options.key; + }; + + /** + * POI周边检索 + * + * @param {Object} options 接口参数对象 + * + * 参数对象结构可以参考 + * @see http://lbs.qq.com/webservice_v1/guide-search.html + */ + search(options) { + var that = this; + options = options || {}; + + Utils.polyfillParam(options); + + if (!Utils.checkKeyword(options)) { + return; + } + + var requestParam = { + keyword: options.keyword, + orderby: options.orderby || '_distance', + page_size: options.page_size || 10, + page_index: options.page_index || 1, + output: 'json', + key: that.key + }; + + if (options.address_format) { + requestParam.address_format = options.address_format; + } + + if (options.filter) { + requestParam.filter = options.filter; + } + + var distance = options.distance || "1000"; + var auto_extend = options.auto_extend || 1; + var region = null; + var rectangle = null; + + //判断城市限定参数 + if (options.region) { + region = options.region; + } + + //矩形限定坐标(暂时只支持字符串格式) + if (options.rectangle) { + rectangle = options.rectangle; + } + + var locationsuccess = function (result) { + if (region && !rectangle) { + //城市限定参数拼接 + requestParam.boundary = "region(" + region + "," + auto_extend + "," + result.latitude + "," + result.longitude + ")"; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'search'); + } + } else if (rectangle && !region) { + //矩形搜索 + requestParam.boundary = "rectangle(" + rectangle + ")"; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'search'); + } + } else { + requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")"; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'search'); + } + } + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_SEARCH, + data: requestParam + }, 'search')); + }; + Utils.locationProcess(options, locationsuccess); + }; + + /** + * sug模糊检索 + * + * @param {Object} options 接口参数对象 + * + * 参数对象结构可以参考 + * http://lbs.qq.com/webservice_v1/guide-suggestion.html + */ + getSuggestion(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + + if (!Utils.checkKeyword(options)) { + return; + } + + var requestParam = { + keyword: options.keyword, + region: options.region || '全国', + region_fix: options.region_fix || 0, + policy: options.policy || 0, + page_size: options.page_size || 10,//控制显示条数 + page_index: options.page_index || 1,//控制页数 + get_subpois : options.get_subpois || 0,//返回子地点 + output: 'json', + key: that.key + }; + //长地址 + if (options.address_format) { + requestParam.address_format = options.address_format; + } + //过滤 + if (options.filter) { + requestParam.filter = options.filter; + } + //排序 + if (options.location) { + var locationsuccess = function (result) { + requestParam.location = result.latitude + ',' + result.longitude; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest'); + } + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_SUGGESTION, + data: requestParam + }, "suggest")); + }; + Utils.locationProcess(options, locationsuccess); + } else { + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest'); + } + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_SUGGESTION, + data: requestParam + }, "suggest")); + } + }; + + /** + * 逆地址解析 + * + * @param {Object} options 接口参数对象 + * + * 请求参数结构可以参考 + * http://lbs.qq.com/webservice_v1/guide-gcoder.html + */ + reverseGeocoder(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + var requestParam = { + coord_type: options.coord_type || 5, + get_poi: options.get_poi || 0, + output: 'json', + key: that.key + }; + if (options.poi_options) { + requestParam.poi_options = options.poi_options + } + + var locationsuccess = function (result) { + requestParam.location = result.latitude + ',' + result.longitude; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'reverseGeocoder'); + } + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_GET_GEOCODER, + data: requestParam + }, 'reverseGeocoder')); + }; + Utils.locationProcess(options, locationsuccess); + }; + + /** + * 地址解析 + * + * @param {Object} options 接口参数对象 + * + * 请求参数结构可以参考 + * http://lbs.qq.com/webservice_v1/guide-geocoder.html + */ + geocoder(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + + if (Utils.checkParamKeyEmpty(options, 'address')) { + return; + } + + var requestParam = { + address: options.address, + output: 'json', + key: that.key + }; + + //城市限定 + if (options.region) { + requestParam.region = options.region; + } + + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'geocoder'); + } + + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_GET_GEOCODER, + data: requestParam + },'geocoder')); + }; + + + /** + * 获取城市列表 + * + * @param {Object} options 接口参数对象 + * + * 请求参数结构可以参考 + * http://lbs.qq.com/webservice_v1/guide-region.html + */ + getCityList(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + var requestParam = { + output: 'json', + key: that.key + }; + + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'getCityList'); + } + + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_CITY_LIST, + data: requestParam + },'getCityList')); + }; + + /** + * 获取对应城市ID的区县列表 + * + * @param {Object} options 接口参数对象 + * + * 请求参数结构可以参考 + * http://lbs.qq.com/webservice_v1/guide-region.html + */ + getDistrictByCityId(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + + if (Utils.checkParamKeyEmpty(options, 'id')) { + return; + } + + var requestParam = { + id: options.id || '', + output: 'json', + key: that.key + }; + + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'getDistrictByCityId'); + } + + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_AREA_LIST, + data: requestParam + },'getDistrictByCityId')); + }; + + /** + * 用于单起点到多终点的路线距离(非直线距离)计算: + * 支持两种距离计算方式:步行和驾车。 + * 起点到终点最大限制直线距离10公里。 + * + * 新增直线距离计算。 + * + * @param {Object} options 接口参数对象 + * + * 请求参数结构可以参考 + * http://lbs.qq.com/webservice_v1/guide-distance.html + */ + calculateDistance(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + + if (Utils.checkParamKeyEmpty(options, 'to')) { + return; + } + + var requestParam = { + mode: options.mode || 'walking', + to: Utils.location2query(options.to), + output: 'json', + key: that.key + }; + + if (options.from) { + options.location = options.from; + } + + //计算直线距离 + if(requestParam.mode == 'straight'){ + var locationsuccess = function (result) { + var locationTo = Utils.getEndLocation(requestParam.to);//处理终点坐标 + var data = { + message:"query ok", + result:{ + elements:[] + }, + status:0 + }; + for (var i = 0; i < locationTo.length; i++) { + data.result.elements.push({//将坐标存入 + distance: Utils.getDistance(result.latitude, result.longitude, locationTo[i].lat, locationTo[i].lng), + duration:0, + from:{ + lat: result.latitude, + lng:result.longitude + }, + to:{ + lat: locationTo[i].lat, + lng: locationTo[i].lng + } + }); + } + var calculateResult = data.result.elements; + var distanceResult = []; + for (var i = 0; i < calculateResult.length; i++) { + distanceResult.push(calculateResult[i].distance); + } + return options.success(data,{ + calculateResult: calculateResult, + distanceResult: distanceResult + }); + }; + + Utils.locationProcess(options, locationsuccess); + } else { + var locationsuccess = function (result) { + requestParam.from = result.latitude + ',' + result.longitude; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'calculateDistance'); + } + wx.request(Utils.buildWxRequestConfig(options, { + url: URL_DISTANCE, + data: requestParam + },'calculateDistance')); + }; + + Utils.locationProcess(options, locationsuccess); + } + }; + + /** + * 路线规划: + * + * @param {Object} options 接口参数对象 + * + * 请求参数结构可以参考 + * https://lbs.qq.com/webservice_v1/guide-road.html + */ + direction(options) { + var that = this; + options = options || {}; + Utils.polyfillParam(options); + + if (Utils.checkParamKeyEmpty(options, 'to')) { + return; + } + + var requestParam = { + output: 'json', + key: that.key + }; + + //to格式处理 + if (typeof options.to == 'string') { + requestParam.to = options.to; + } else { + requestParam.to = options.to.latitude + ',' + options.to.longitude; + } + //初始化局部请求域名 + var SET_URL_DIRECTION = null; + //设置默认mode属性 + options.mode = options.mode || MODE.driving; + + //设置请求域名 + SET_URL_DIRECTION = URL_DIRECTION + options.mode; + + if (options.from) { + options.location = options.from; + } + + if (options.mode == MODE.driving) { + if (options.from_poi) { + requestParam.from_poi = options.from_poi; + } + if (options.heading) { + requestParam.heading = options.heading; + } + if (options.speed) { + requestParam.speed = options.speed; + } + if (options.accuracy) { + requestParam.accuracy = options.accuracy; + } + if (options.road_type) { + requestParam.road_type = options.road_type; + } + if (options.to_poi) { + requestParam.to_poi = options.to_poi; + } + if (options.from_track) { + requestParam.from_track = options.from_track; + } + if (options.waypoints) { + requestParam.waypoints = options.waypoints; + } + if (options.policy) { + requestParam.policy = options.policy; + } + if (options.plate_number) { + requestParam.plate_number = options.plate_number; + } + } + + if (options.mode == MODE.transit) { + if (options.departure_time) { + requestParam.departure_time = options.departure_time; + } + if (options.policy) { + requestParam.policy = options.policy; + } + } + + var locationsuccess = function (result) { + requestParam.from = result.latitude + ',' + result.longitude; + if (options.sig) { + requestParam.sig = Utils.getSig(requestParam, options.sig, 'direction',options.mode); + } + wx.request(Utils.buildWxRequestConfig(options, { + url: SET_URL_DIRECTION, + data: requestParam + }, 'direction')); + }; + + Utils.locationProcess(options, locationsuccess); + } +}; + +module.exports = QQMapWX; \ No newline at end of file diff --git a/utils/qqmap-wx-jssdk.min.js b/utils/qqmap-wx-jssdk.min.js new file mode 100644 index 0000000..8fa1477 --- /dev/null +++ b/utils/qqmap-wx-jssdk.min.js @@ -0,0 +1 @@ +var ERROR_CONF = { KEY_ERR: 311, KEY_ERR_MSG: 'key格式错误', PARAM_ERR: 310, PARAM_ERR_MSG: '请求参数信息有误', SYSTEM_ERR: 600, SYSTEM_ERR_MSG: '系统错误', WX_ERR_CODE: 1000, WX_OK_CODE: 200 }; var BASE_URL = 'https://apis.map.qq.com/ws/'; var URL_SEARCH = BASE_URL + 'place/v1/search'; var URL_SUGGESTION = BASE_URL + 'place/v1/suggestion'; var URL_GET_GEOCODER = BASE_URL + 'geocoder/v1/'; var URL_CITY_LIST = BASE_URL + 'district/v1/list'; var URL_AREA_LIST = BASE_URL + 'district/v1/getchildren'; var URL_DISTANCE = BASE_URL + 'distance/v1/'; var URL_DIRECTION = BASE_URL + 'direction/v1/'; var MODE = { driving: 'driving', transit: 'transit' }; var EARTH_RADIUS = 6378136.49; var Utils = { safeAdd(x, y) { var lsw = (x & 0xffff) + (y & 0xffff); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xffff) }, bitRotateLeft(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)) }, md5cmn(q, a, b, x, s, t) { return this.safeAdd(this.bitRotateLeft(this.safeAdd(this.safeAdd(a, q), this.safeAdd(x, t)), s), b) }, md5ff(a, b, c, d, x, s, t) { return this.md5cmn((b & c) | (~b & d), a, b, x, s, t) }, md5gg(a, b, c, d, x, s, t) { return this.md5cmn((b & d) | (c & ~d), a, b, x, s, t) }, md5hh(a, b, c, d, x, s, t) { return this.md5cmn(b ^ c ^ d, a, b, x, s, t) }, md5ii(a, b, c, d, x, s, t) { return this.md5cmn(c ^ (b | ~d), a, b, x, s, t) }, binlMD5(x, len) { x[len >> 5] |= 0x80 << (len % 32); x[((len + 64) >>> 9 << 4) + 14] = len; var i; var olda; var oldb; var oldc; var oldd; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for (i = 0; i < x.length; i += 16) { olda = a; oldb = b; oldc = c; oldd = d; a = this.md5ff(a, b, c, d, x[i], 7, -680876936); d = this.md5ff(d, a, b, c, x[i + 1], 12, -389564586); c = this.md5ff(c, d, a, b, x[i + 2], 17, 606105819); b = this.md5ff(b, c, d, a, x[i + 3], 22, -1044525330); a = this.md5ff(a, b, c, d, x[i + 4], 7, -176418897); d = this.md5ff(d, a, b, c, x[i + 5], 12, 1200080426); c = this.md5ff(c, d, a, b, x[i + 6], 17, -1473231341); b = this.md5ff(b, c, d, a, x[i + 7], 22, -45705983); a = this.md5ff(a, b, c, d, x[i + 8], 7, 1770035416); d = this.md5ff(d, a, b, c, x[i + 9], 12, -1958414417); c = this.md5ff(c, d, a, b, x[i + 10], 17, -42063); b = this.md5ff(b, c, d, a, x[i + 11], 22, -1990404162); a = this.md5ff(a, b, c, d, x[i + 12], 7, 1804603682); d = this.md5ff(d, a, b, c, x[i + 13], 12, -40341101); c = this.md5ff(c, d, a, b, x[i + 14], 17, -1502002290); b = this.md5ff(b, c, d, a, x[i + 15], 22, 1236535329); a = this.md5gg(a, b, c, d, x[i + 1], 5, -165796510); d = this.md5gg(d, a, b, c, x[i + 6], 9, -1069501632); c = this.md5gg(c, d, a, b, x[i + 11], 14, 643717713); b = this.md5gg(b, c, d, a, x[i], 20, -373897302); a = this.md5gg(a, b, c, d, x[i + 5], 5, -701558691); d = this.md5gg(d, a, b, c, x[i + 10], 9, 38016083); c = this.md5gg(c, d, a, b, x[i + 15], 14, -660478335); b = this.md5gg(b, c, d, a, x[i + 4], 20, -405537848); a = this.md5gg(a, b, c, d, x[i + 9], 5, 568446438); d = this.md5gg(d, a, b, c, x[i + 14], 9, -1019803690); c = this.md5gg(c, d, a, b, x[i + 3], 14, -187363961); b = this.md5gg(b, c, d, a, x[i + 8], 20, 1163531501); a = this.md5gg(a, b, c, d, x[i + 13], 5, -1444681467); d = this.md5gg(d, a, b, c, x[i + 2], 9, -51403784); c = this.md5gg(c, d, a, b, x[i + 7], 14, 1735328473); b = this.md5gg(b, c, d, a, x[i + 12], 20, -1926607734); a = this.md5hh(a, b, c, d, x[i + 5], 4, -378558); d = this.md5hh(d, a, b, c, x[i + 8], 11, -2022574463); c = this.md5hh(c, d, a, b, x[i + 11], 16, 1839030562); b = this.md5hh(b, c, d, a, x[i + 14], 23, -35309556); a = this.md5hh(a, b, c, d, x[i + 1], 4, -1530992060); d = this.md5hh(d, a, b, c, x[i + 4], 11, 1272893353); c = this.md5hh(c, d, a, b, x[i + 7], 16, -155497632); b = this.md5hh(b, c, d, a, x[i + 10], 23, -1094730640); a = this.md5hh(a, b, c, d, x[i + 13], 4, 681279174); d = this.md5hh(d, a, b, c, x[i], 11, -358537222); c = this.md5hh(c, d, a, b, x[i + 3], 16, -722521979); b = this.md5hh(b, c, d, a, x[i + 6], 23, 76029189); a = this.md5hh(a, b, c, d, x[i + 9], 4, -640364487); d = this.md5hh(d, a, b, c, x[i + 12], 11, -421815835); c = this.md5hh(c, d, a, b, x[i + 15], 16, 530742520); b = this.md5hh(b, c, d, a, x[i + 2], 23, -995338651); a = this.md5ii(a, b, c, d, x[i], 6, -198630844); d = this.md5ii(d, a, b, c, x[i + 7], 10, 1126891415); c = this.md5ii(c, d, a, b, x[i + 14], 15, -1416354905); b = this.md5ii(b, c, d, a, x[i + 5], 21, -57434055); a = this.md5ii(a, b, c, d, x[i + 12], 6, 1700485571); d = this.md5ii(d, a, b, c, x[i + 3], 10, -1894986606); c = this.md5ii(c, d, a, b, x[i + 10], 15, -1051523); b = this.md5ii(b, c, d, a, x[i + 1], 21, -2054922799); a = this.md5ii(a, b, c, d, x[i + 8], 6, 1873313359); d = this.md5ii(d, a, b, c, x[i + 15], 10, -30611744); c = this.md5ii(c, d, a, b, x[i + 6], 15, -1560198380); b = this.md5ii(b, c, d, a, x[i + 13], 21, 1309151649); a = this.md5ii(a, b, c, d, x[i + 4], 6, -145523070); d = this.md5ii(d, a, b, c, x[i + 11], 10, -1120210379); c = this.md5ii(c, d, a, b, x[i + 2], 15, 718787259); b = this.md5ii(b, c, d, a, x[i + 9], 21, -343485551); a = this.safeAdd(a, olda); b = this.safeAdd(b, oldb); c = this.safeAdd(c, oldc); d = this.safeAdd(d, oldd) } return [a, b, c, d] }, binl2rstr(input) { var i; var output = ''; var length32 = input.length * 32; for (i = 0; i < length32; i += 8) { output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff) } return output }, rstr2binl(input) { var i; var output = []; output[(input.length >> 2) - 1] = undefined; for (i = 0; i < output.length; i += 1) { output[i] = 0 } var length8 = input.length * 8; for (i = 0; i < length8; i += 8) { output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32) } return output }, rstrMD5(s) { return this.binl2rstr(this.binlMD5(this.rstr2binl(s), s.length * 8)) }, rstrHMACMD5(key, data) { var i; var bkey = this.rstr2binl(key); var ipad = []; var opad = []; var hash; ipad[15] = opad[15] = undefined; if (bkey.length > 16) { bkey = this.binlMD5(bkey, key.length * 8) } for (i = 0; i < 16; i += 1) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5c5c5c5c } hash = this.binlMD5(ipad.concat(this.rstr2binl(data)), 512 + data.length * 8); return this.binl2rstr(this.binlMD5(opad.concat(hash), 512 + 128)) }, rstr2hex(input) { var hexTab = '0123456789abcdef'; var output = ''; var x; var i; for (i = 0; i < input.length; i += 1) { x = input.charCodeAt(i); output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f) } return output }, str2rstrUTF8(input) { return unescape(encodeURIComponent(input)) }, rawMD5(s) { return this.rstrMD5(this.str2rstrUTF8(s)) }, hexMD5(s) { return this.rstr2hex(this.rawMD5(s)) }, rawHMACMD5(k, d) { return this.rstrHMACMD5(this.str2rstrUTF8(k), str2rstrUTF8(d)) }, hexHMACMD5(k, d) { return this.rstr2hex(this.rawHMACMD5(k, d)) }, md5(string, key, raw) { if (!key) { if (!raw) { return this.hexMD5(string) } return this.rawMD5(string) } if (!raw) { return this.hexHMACMD5(key, string) } return this.rawHMACMD5(key, string) }, getSig(requestParam, sk, feature, mode) { var sig = null; var requestArr = []; Object.keys(requestParam).sort().forEach(function (key) { requestArr.push(key + '=' + requestParam[key]) }); if (feature == 'search') { sig = '/ws/place/v1/search?' + requestArr.join('&') + sk } if (feature == 'suggest') { sig = '/ws/place/v1/suggestion?' + requestArr.join('&') + sk } if (feature == 'reverseGeocoder') { sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk } if (feature == 'geocoder') { sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk } if (feature == 'getCityList') { sig = '/ws/district/v1/list?' + requestArr.join('&') + sk } if (feature == 'getDistrictByCityId') { sig = '/ws/district/v1/getchildren?' + requestArr.join('&') + sk } if (feature == 'calculateDistance') { sig = '/ws/distance/v1/?' + requestArr.join('&') + sk } if (feature == 'direction') { sig = '/ws/direction/v1/' + mode + '?' + requestArr.join('&') + sk } sig = this.md5(sig); return sig }, location2query(data) { if (typeof data == 'string') { return data } var query = ''; for (var i = 0; i < data.length; i++) { var d = data[i]; if (!!query) { query += ';' } if (d.location) { query = query + d.location.lat + ',' + d.location.lng } if (d.latitude && d.longitude) { query = query + d.latitude + ',' + d.longitude } } return query }, rad(d) { return d * Math.PI / 180.0 }, getEndLocation(location) { var to = location.split(';'); var endLocation = []; for (var i = 0; i < to.length; i++) { endLocation.push({ lat: parseFloat(to[i].split(',')[0]), lng: parseFloat(to[i].split(',')[1]) }) } return endLocation }, getDistance(latFrom, lngFrom, latTo, lngTo) { var radLatFrom = this.rad(latFrom); var radLatTo = this.rad(latTo); var a = radLatFrom - radLatTo; var b = this.rad(lngFrom) - this.rad(lngTo); var distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLatFrom) * Math.cos(radLatTo) * Math.pow(Math.sin(b / 2), 2))); distance = distance * EARTH_RADIUS; distance = Math.round(distance * 10000) / 10000; return parseFloat(distance.toFixed(0)) }, getWXLocation(success, fail, complete) { wx.getLocation({ type: 'gcj02', success: success, fail: fail, complete: complete }) }, getLocationParam(location) { if (typeof location == 'string') { var locationArr = location.split(','); if (locationArr.length === 2) { location = { latitude: location.split(',')[0], longitude: location.split(',')[1] } } else { location = {} } } return location }, polyfillParam(param) { param.success = param.success || function () { }; param.fail = param.fail || function () { }; param.complete = param.complete || function () { } }, checkParamKeyEmpty(param, key) { if (!param[key]) { var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + key + '参数格式有误'); param.fail(errconf); param.complete(errconf); return true } return false }, checkKeyword(param) { return !this.checkParamKeyEmpty(param, 'keyword') }, checkLocation(param) { var location = this.getLocationParam(param.location); if (!location || !location.latitude || !location.longitude) { var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + ' location参数格式有误'); param.fail(errconf); param.complete(errconf); return false } return true }, buildErrorConfig(errCode, errMsg) { return { status: errCode, message: errMsg } }, handleData(param, data, feature) { if (feature == 'search') { var searchResult = data.data; var searchSimplify = []; for (var i = 0; i < searchResult.length; i++) { searchSimplify.push({ id: searchResult[i].id || null, title: searchResult[i].title || null, latitude: searchResult[i].location && searchResult[i].location.lat || null, longitude: searchResult[i].location && searchResult[i].location.lng || null, address: searchResult[i].address || null, category: searchResult[i].category || null, tel: searchResult[i].tel || null, adcode: searchResult[i].ad_info && searchResult[i].ad_info.adcode || null, city: searchResult[i].ad_info && searchResult[i].ad_info.city || null, district: searchResult[i].ad_info && searchResult[i].ad_info.district || null, province: searchResult[i].ad_info && searchResult[i].ad_info.province || null }) } param.success(data, { searchResult: searchResult, searchSimplify: searchSimplify }) } else if (feature == 'suggest') { var suggestResult = data.data; var suggestSimplify = []; for (var i = 0; i < suggestResult.length; i++) { suggestSimplify.push({ adcode: suggestResult[i].adcode || null, address: suggestResult[i].address || null, category: suggestResult[i].category || null, city: suggestResult[i].city || null, district: suggestResult[i].district || null, id: suggestResult[i].id || null, latitude: suggestResult[i].location && suggestResult[i].location.lat || null, longitude: suggestResult[i].location && suggestResult[i].location.lng || null, province: suggestResult[i].province || null, title: suggestResult[i].title || null, type: suggestResult[i].type || null }) } param.success(data, { suggestResult: suggestResult, suggestSimplify: suggestSimplify }) } else if (feature == 'reverseGeocoder') { var reverseGeocoderResult = data.result; var reverseGeocoderSimplify = { address: reverseGeocoderResult.address || null, latitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lat || null, longitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lng || null, adcode: reverseGeocoderResult.ad_info && reverseGeocoderResult.ad_info.adcode || null, city: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.city || null, district: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.district || null, nation: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.nation || null, province: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.province || null, street: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street || null, street_number: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street_number || null, recommend: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.recommend || null, rough: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.rough || null }; if (reverseGeocoderResult.pois) { var pois = reverseGeocoderResult.pois; var poisSimplify = []; for (var i = 0; i < pois.length; i++) { poisSimplify.push({ id: pois[i].id || null, title: pois[i].title || null, latitude: pois[i].location && pois[i].location.lat || null, longitude: pois[i].location && pois[i].location.lng || null, address: pois[i].address || null, category: pois[i].category || null, adcode: pois[i].ad_info && pois[i].ad_info.adcode || null, city: pois[i].ad_info && pois[i].ad_info.city || null, district: pois[i].ad_info && pois[i].ad_info.district || null, province: pois[i].ad_info && pois[i].ad_info.province || null }) } param.success(data, { reverseGeocoderResult: reverseGeocoderResult, reverseGeocoderSimplify: reverseGeocoderSimplify, pois: pois, poisSimplify: poisSimplify }) } else { param.success(data, { reverseGeocoderResult: reverseGeocoderResult, reverseGeocoderSimplify: reverseGeocoderSimplify }) } } else if (feature == 'geocoder') { var geocoderResult = data.result; var geocoderSimplify = { title: geocoderResult.title || null, latitude: geocoderResult.location && geocoderResult.location.lat || null, longitude: geocoderResult.location && geocoderResult.location.lng || null, adcode: geocoderResult.ad_info && geocoderResult.ad_info.adcode || null, province: geocoderResult.address_components && geocoderResult.address_components.province || null, city: geocoderResult.address_components && geocoderResult.address_components.city || null, district: geocoderResult.address_components && geocoderResult.address_components.district || null, street: geocoderResult.address_components && geocoderResult.address_components.street || null, street_number: geocoderResult.address_components && geocoderResult.address_components.street_number || null, level: geocoderResult.level || null }; param.success(data, { geocoderResult: geocoderResult, geocoderSimplify: geocoderSimplify }) } else if (feature == 'getCityList') { var provinceResult = data.result[0]; var cityResult = data.result[1]; var districtResult = data.result[2]; param.success(data, { provinceResult: provinceResult, cityResult: cityResult, districtResult: districtResult }) } else if (feature == 'getDistrictByCityId') { var districtByCity = data.result[0]; param.success(data, districtByCity) } else if (feature == 'calculateDistance') { var calculateDistanceResult = data.result.elements; var distance = []; for (var i = 0; i < calculateDistanceResult.length; i++) { distance.push(calculateDistanceResult[i].distance) } param.success(data, { calculateDistanceResult: calculateDistanceResult, distance: distance }) } else if (feature == 'direction') { var direction = data.result.routes; param.success(data, direction) } else { param.success(data) } }, buildWxRequestConfig(param, options, feature) { var that = this; options.header = { "content-type": "application/json" }; options.method = 'GET'; options.success = function (res) { var data = res.data; if (data.status === 0) { that.handleData(param, data, feature) } else { param.fail(data) } }; options.fail = function (res) { res.statusCode = ERROR_CONF.WX_ERR_CODE; param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)) }; options.complete = function (res) { var statusCode = +res.statusCode; switch (statusCode) { case ERROR_CONF.WX_ERR_CODE: { param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); break } case ERROR_CONF.WX_OK_CODE: { var data = res.data; if (data.status === 0) { param.complete(data) } else { param.complete(that.buildErrorConfig(data.status, data.message)) } break } default: { param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR, ERROR_CONF.SYSTEM_ERR_MSG)) } } }; return options }, locationProcess(param, locationsuccess, locationfail, locationcomplete) { var that = this; locationfail = locationfail || function (res) { res.statusCode = ERROR_CONF.WX_ERR_CODE; param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)) }; locationcomplete = locationcomplete || function (res) { if (res.statusCode == ERROR_CONF.WX_ERR_CODE) { param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)) } }; if (!param.location) { that.getWXLocation(locationsuccess, locationfail, locationcomplete) } else if (that.checkLocation(param)) { var location = Utils.getLocationParam(param.location); locationsuccess(location) } } }; class QQMapWX { constructor(options) { if (!options.key) { throw Error('key值不能为空') } this.key = options.key }; search(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (!Utils.checkKeyword(options)) { return } var requestParam = { keyword: options.keyword, orderby: options.orderby || '_distance', page_size: options.page_size || 10, page_index: options.page_index || 1, output: 'json', key: that.key }; if (options.address_format) { requestParam.address_format = options.address_format } if (options.filter) { requestParam.filter = options.filter } var distance = options.distance || "1000"; var auto_extend = options.auto_extend || 1; var region = null; var rectangle = null; if (options.region) { region = options.region } if (options.rectangle) { rectangle = options.rectangle } var locationsuccess = function (result) { if (region && !rectangle) { requestParam.boundary = "region(" + region + "," + auto_extend + "," + result.latitude + "," + result.longitude + ")"; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'search') } } else if (rectangle && !region) { requestParam.boundary = "rectangle(" + rectangle + ")"; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'search') } } else { requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")"; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'search') } } wx.request(Utils.buildWxRequestConfig(options, { url: URL_SEARCH, data: requestParam }, 'search')) }; Utils.locationProcess(options, locationsuccess) }; getSuggestion(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (!Utils.checkKeyword(options)) { return } var requestParam = { keyword: options.keyword, region: options.region || '全国', region_fix: options.region_fix || 0, policy: options.policy || 0, page_size: options.page_size || 10, page_index: options.page_index || 1, get_subpois: options.get_subpois || 0, output: 'json', key: that.key }; if (options.address_format) { requestParam.address_format = options.address_format } if (options.filter) { requestParam.filter = options.filter } if (options.location) { var locationsuccess = function (result) { requestParam.location = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_SUGGESTION, data: requestParam }, "suggest")) }; Utils.locationProcess(options, locationsuccess) } else { if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_SUGGESTION, data: requestParam }, "suggest")) } }; reverseGeocoder(options) { var that = this; options = options || {}; Utils.polyfillParam(options); var requestParam = { coord_type: options.coord_type || 5, get_poi: options.get_poi || 0, output: 'json', key: that.key }; if (options.poi_options) { requestParam.poi_options = options.poi_options } var locationsuccess = function (result) { requestParam.location = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'reverseGeocoder') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_GET_GEOCODER, data: requestParam }, 'reverseGeocoder')) }; Utils.locationProcess(options, locationsuccess) }; geocoder(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'address')) { return } var requestParam = { address: options.address, output: 'json', key: that.key }; if (options.region) { requestParam.region = options.region } if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'geocoder') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_GET_GEOCODER, data: requestParam }, 'geocoder')) }; getCityList(options) { var that = this; options = options || {}; Utils.polyfillParam(options); var requestParam = { output: 'json', key: that.key }; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'getCityList') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_CITY_LIST, data: requestParam }, 'getCityList')) }; getDistrictByCityId(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'id')) { return } var requestParam = { id: options.id || '', output: 'json', key: that.key }; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'getDistrictByCityId') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_AREA_LIST, data: requestParam }, 'getDistrictByCityId')) }; calculateDistance(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'to')) { return } var requestParam = { mode: options.mode || 'walking', to: Utils.location2query(options.to), output: 'json', key: that.key }; if (options.from) { options.location = options.from } if (requestParam.mode == 'straight') { var locationsuccess = function (result) { var locationTo = Utils.getEndLocation(requestParam.to); var data = { message: "query ok", result: { elements: [] }, status: 0 }; for (var i = 0; i < locationTo.length; i++) { data.result.elements.push({ distance: Utils.getDistance(result.latitude, result.longitude, locationTo[i].lat, locationTo[i].lng), duration: 0, from: { lat: result.latitude, lng: result.longitude }, to: { lat: locationTo[i].lat, lng: locationTo[i].lng } }) } var calculateResult = data.result.elements; var distanceResult = []; for (var i = 0; i < calculateResult.length; i++) { distanceResult.push(calculateResult[i].distance) } return options.success(data, { calculateResult: calculateResult, distanceResult: distanceResult }) }; Utils.locationProcess(options, locationsuccess) } else { var locationsuccess = function (result) { requestParam.from = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'calculateDistance') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_DISTANCE, data: requestParam }, 'calculateDistance')) }; Utils.locationProcess(options, locationsuccess) } }; direction(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'to')) { return } var requestParam = { output: 'json', key: that.key }; if (typeof options.to == 'string') { requestParam.to = options.to } else { requestParam.to = options.to.latitude + ',' + options.to.longitude } var SET_URL_DIRECTION = null; options.mode = options.mode || MODE.driving; SET_URL_DIRECTION = URL_DIRECTION + options.mode; if (options.from) { options.location = options.from } if (options.mode == MODE.driving) { if (options.from_poi) { requestParam.from_poi = options.from_poi } if (options.heading) { requestParam.heading = options.heading } if (options.speed) { requestParam.speed = options.speed } if (options.accuracy) { requestParam.accuracy = options.accuracy } if (options.road_type) { requestParam.road_type = options.road_type } if (options.to_poi) { requestParam.to_poi = options.to_poi } if (options.from_track) { requestParam.from_track = options.from_track } if (options.waypoints) { requestParam.waypoints = options.waypoints } if (options.policy) { requestParam.policy = options.policy } if (options.plate_number) { requestParam.plate_number = options.plate_number } } if (options.mode == MODE.transit) { if (options.departure_time) { requestParam.departure_time = options.departure_time } if (options.policy) { requestParam.policy = options.policy } } var locationsuccess = function (result) { requestParam.from = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'direction', options.mode) } wx.request(Utils.buildWxRequestConfig(options, { url: SET_URL_DIRECTION, data: requestParam }, 'direction')) }; Utils.locationProcess(options, locationsuccess) } }; module.exports = QQMapWX; \ No newline at end of file From c9b285e4e982a2504739365ce95d510481425791 Mon Sep 17 00:00:00 2001 From: dengj <209192278@qq.com> Date: Tue, 31 Oct 2023 17:46:59 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E9=82=93=E6=B4=81=20:=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89tabbar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.vue | 5 +- components/TabBar/TabBar.vue | 157 ++++++++++++++++++++++++++++ main.js | 1 - manifest.json | 6 +- pages.json | 2 +- pages/index/index.vue | 5 +- pages/my/my.vue | 1 + pages/publish/publish.vue | 1 + pages/shopAddress/shopAddress.vue | 1 + pages/shopTransfer/shopTransfer.vue | 1 + static/tabbar/di_icon_fb@2x.png | Bin 0 -> 27047 bytes 11 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 components/TabBar/TabBar.vue create mode 100644 static/tabbar/di_icon_fb@2x.png diff --git a/App.vue b/App.vue index 8c2b732..6d6d52b 100644 --- a/App.vue +++ b/App.vue @@ -1,3 +1,6 @@ + + + + \ No newline at end of file diff --git a/main.js b/main.js index bf3085a..e035a76 100644 --- a/main.js +++ b/main.js @@ -6,7 +6,6 @@ import { toast } from "./service/request.js" Vue.use(uView) - Vue.prototype.$api = apiService Vue.prototype.$toast = toast diff --git a/manifest.json b/manifest.json index 6ca8e84..e3780b6 100644 --- a/manifest.json +++ b/manifest.json @@ -55,11 +55,7 @@ "urlCheck" : false }, "usingComponents" : true, - "permission" : { - "scope.userLocation" : { - "desc" : "" - } - } + "permission" : {} }, "mp-alipay" : { "usingComponents" : true diff --git a/pages.json b/pages.json index 9b22b8e..4a76590 100644 --- a/pages.json +++ b/pages.json @@ -59,9 +59,9 @@ ], "tabBar": { "color": "#CCCCCC", - "selectedColor": "#0EBB5B", "borderStyle": "white", "backgroundColor": "#FFFFFF", + "custom":true, "list": [{ "pagePath": "pages/index/index", "text": "首页", diff --git a/pages/index/index.vue b/pages/index/index.vue index bcea44e..537ac72 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -1,6 +1,7 @@ - @@ -18,7 +19,7 @@ } \ No newline at end of file diff --git a/pages/my/my.vue b/pages/my/my.vue index 6e7c990..ecb41eb 100644 --- a/pages/my/my.vue +++ b/pages/my/my.vue @@ -1,6 +1,7 @@+ + 我的 + diff --git a/pages/publish/publish.vue b/pages/publish/publish.vue index 6573129..5f2e4ca 100644 --- a/pages/publish/publish.vue +++ b/pages/publish/publish.vue @@ -1,6 +1,7 @@发布 + diff --git a/pages/shopAddress/shopAddress.vue b/pages/shopAddress/shopAddress.vue index 941c94b..e467055 100644 --- a/pages/shopAddress/shopAddress.vue +++ b/pages/shopAddress/shopAddress.vue @@ -1,6 +1,7 @@找店地址 + diff --git a/pages/shopTransfer/shopTransfer.vue b/pages/shopTransfer/shopTransfer.vue index 2041ac9..7cbd61a 100644 --- a/pages/shopTransfer/shopTransfer.vue +++ b/pages/shopTransfer/shopTransfer.vue @@ -1,6 +1,7 @@店铺转让 + diff --git a/static/tabbar/di_icon_fb@2x.png b/static/tabbar/di_icon_fb@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..02731a321b7565d4ece26614fb2e77fdaebc2f0b GIT binary patch literal 27047 zcmV)VK(D`vP)PyA07*naRCr$Py?MBuRgo{e); Ar+O$ROwifwr4ycgsB3 zwyoEJK}N$A2q4%pYOC1d?Rz_p^mPDa2oMrTLPYHTx>Xbhd}J0H1VVD&^*#GttEzrg ztKNN1lARDB`2&)3_FnHAYWUT!s@5CB`af%A2ll(?+^v=^3p Z<_Pr3d zX+n5;Xwo(zhL?vJHjOE6ltQy%N^zrJ2pgt6o99AI%VLVpH6bkvDgH6W^k_)okr2Y8 zA*Dw`ulHaG;a4Lm-nY?a;aA_=`J_Lrk%hd(2aPZB^{@8w-@Wv6+pbvg%+4!fvvUmb zt)WRfhZtU;nzTiTA*2-g|I7bL{ePzrWBx^78Oo3IXUd=cciIob05Qb&yY8Pn<`W^t zdqYb1G%5b1*9-SdoEY!(gD@T?upVp)_Ev05^3gNYV zfoI|Mq#otE)tJ2P^c_-?RwqIVtupZc+Yc5k6TM+&Yn4wFuK)8geEW VhG z8j0bin OZwyM6=aO#?|X>l>FKFWlct6griBpR*c$R!tbY;yEac@Mpb#YJ z?QdJ*&B{a@Px_P Bd^TcL@n}4v^dJi*5 z1lB8vvpdt5Ua)%{ZDyvBrZ*wHC8pG>Ll$-tWTge#!ULpYs6-k-*1pn=z8H&=DWO*5 z DjkcccfYf$kN2!F^K01Tp-MBtVYWQ<)3oO0tBJ7!S` z1^-w8KsyWM>yOzB;ocZWuAY$6)z?os?Y{NOB6ja3xfe5*oYxPeXQmVnNg+&5O_Sqk z2(HObklg3r0hChFHEv@TLeJ83n9@S6z5)_lQ+TZmRtqy>D0D(Prm@}*VH(Vl;-Ru0 z9xukeO_(2Iyn4bW6XxEq+ozs*NeW2WwwKh}XQkAef7hIMH!&U>nsh))X(GlGq#>vT zq7;JjD+ole2Lf &Nn_Zi=HGtt z*${jG+KcI{Q}#Ul2eV>qUP=P XjhBSY;Au zC+?`2*Ak2a9O4jy97OR#tYj1;v`~&TMVKz-*2u3ENQDGf{$?42(V+D+FaVRxBJv0u zl~>A>_<0E7+&68u!`HsB+Xt7w6cpt}uONrtch$t-KKAfYAvGs7DZK_MRJNMNc(Y&- z*5V{a4OLjtD6e5X2ncdZ;UXoBx?mLzVgqyl4E2iEWlu+e3Q@e6Gbz6Z&!J$SonPVC z+HuRUybYY23BT!$#PdV*nlH_pdc?CYW<`0?D#*eAe%WS!c;?B!Z9@EHNNI=m5Lu22 z_Af$%)T@rgLHP6lg(V`oR#U8&!ey&GFt8^vGcgBnTRbicH84~T#jFI^#2eN-%GWjP zCCVX5&B9mrXZAo0;WHs@d*!^TAAah^s3 6cYfQK?D|+jO0O8d~Jm<3z|G%)t3;oGQl(1Yy7c5Ld>+o96hqC zqdY~{4+&1lmnc}(>S7TUgmeJy`XA|q@I>szQ@7pwzg_Y5ICJ#HpeQd21=(lG1%Eag zn#)s2yXF{GmuuvMlHgex@gnHrJS51qtP+pw)Kf7)QbD$XK#uodK`r=Rm7i3GTjB{n zzah$s3>qpMc{Kh$W%sKjC~@85rE1qv_PQOEce!s2mX5@czq@(b>36=+mE;AjAp8FN zMO&|UcKNv}#A8CqVR#3E&_Tr;#rk&&Th=T10|BqZ#gJXsIh3N778U6+O)%amgsMJ^ zr4ezSR7E<}Z&|9!@!0a0PGR=EM%f!QMgqw~h`o?vi2pcoVm#@(NwXe%p(@G?QbAHm z@tr@q;E1M4b3#blsKQr{IRuki1>iWr);2jYh Z!81H7#|5So_NdDPhS=L3CI`N zpBJ2h?7Q?cZ(E*LTpm)Il=nKDaty?k%`b(4bTTB!ZB&4;8fZ-?J-~sm&5ol2>Ed rwpV<`ioi;dMb z#t;^a^fu_jt{=aUbmRr2AbqbfW9bDag_O=rA&s<~++mNZGICWAtB8Lw)VLEE$57?1 z)5Bp|DxqO 5Hx^4Eo>qBsHPQwwtOqGf_4sF?TRaTUP; zezk+`A`e3j&r;^382oisT8YPOIZce=`iYy29CH00vmRR4y~#SSAn#my{* hj6qERLrMAQw!yE+KbzX-~6m^7ADVVAO1 zuiYpb4rJc!mf=oRV=*70v;UMA%J8%<#?<2|%af0 y~v{N!D2f z=@%8=cGvl*gb+TRA(bw%rQQrWBx}jU%92+hi;p;f5LTT?q~|FCRzWlfrqW1r+=x*W zbjc&5VqsF!w%96RhIU=l8}e$>4+6n52y<3;cDG8&ETqz_$#Yf^u%3YO;_CafncR9D zMnf;0F@5?5=gf+;*2yBsby7j5|KzjVhv%OAT56gZ2uB#>mplgxgafH6z8_Bt4vKy( z`3T9pbAuEJl-CYh#|I)v*nggFE(GG-_#{0bI&%-|2?8xJ2ZMWTloEnqVC-VOQrQg5 z3E8S;PNagJA?T{TswNz)L2LJg*58XaY#1kg;KmuJ^e>`Vr~a&S3Nn4koT(|qe-5F^ z^;52Ot_86AC>u|Mv$ZK!75_H4XA%c0W3d9ahJ5x}9sM9&2Wa}wy*R*nAf$0AkqB@o zE1}a5Qp660Stn@xy{0mjy5z-ZI(j8*jQHQ$G7+RKbABME_}90*>&% fJJeUdT2zsZ2c( z30+Ja3$J0SJXXodp9{~r7%#YWMFrrHS=X@`LPHY+Sv(4oZet pF;#SO z4oo8@l{rxXVwpX`{zAX%m;*uq&;rSC=#bjNAf6U@AvP2$;gjvP%aND)VL>LZUll`w z_u%Krn5<}!wB;DGOw?{4emlf)-28pcxoBNbl668srr&k`oRpdq7_xvabXy+C`YK`{ zJP7SN<7LF=Sx`{X$XjGZ!y^Rgu(Ab~nblHd^L-Xbl71GCux7GJK*9mD;(41`s#(t! z+OeL)C _UkP*vcz8|F(CXb>j1_B+sjY%t|+J zaNAvrzL-Kd465CnJrUYf(WOO*>r(FyGeti(2d(tTSb4U#UVhOe5lOF^OmLc!sN=6o zXu8-XjCYjLXyc;+m&z$^v0g|5d)Bk!5p-2^-Z)Xzj$~_fa*U6G;)TeEpXJX#hVYe< zjV2s3Z|bZS&zGV+ZwhkoZ!g;Tu?L^~dJ1triZ^O&=39BTzRU_iS%-rjuwoVwm%tL~ z+fYF`lz+ >(q*Z zX HRza1;5dBf*l1RB6&nbx@{$-5edpo@B 41JKZ~hQl^O&oim!58k`Fky5#-yx?LS z7KF_<+kgI^YybY?wXPtoax8oD))3QMuy;eOxt7R0LAaZ$_
d}Xm-@ui) zSWyA=sV$$d8>Rwi@(x|@p94mxEu+=N0T(F{e5kP)J1m)7?SYhaF7i+zK!jHwhHx6d ztPo1D>zH7GKoZB)3hD`VHsN*?bmU%>C^bQ*7`M(#D?AUBm6d-J }M}eAkjq(E{9X&c<)ZC;*e`*%1N9N6I97#6?+ObqiJPp>Bak0iA0v! z8k$*HrgJ5tN>yHi91dFg$_+r@y}4$nGpKj^Ijn6!B@;E%6#{IlI)iY_8Pn+je6)GX zveuZw_cqvM!-LjV;J(%rWcrdhUr8Yy#<)`9BDrhU6B=pR100Mq2P-?C1RE9@S`1zr z@jN5RN9a-!Qe?4n2xI(<6m)K*%z*PUdItJFU_)(N_|oBlXpO2b9>R(imU_yDl(5(e zr}xHhXZC4aBl*QaF_EI?Axcj3%VUPG+`ixJBfRAf`)6xKK`_r@lTfNOT_x+#K1un6 zU(u`8N@d464j^IG olG`x;e{er;8gny=>9 z2iPlj;J`?ZXcrm8f~nEu791pOW%(YU0e+*C1flraC%@tXNdo0>6h`kTRkxA=kila1 z_M@;a3#Te+RqT?s&^Q(v4pIn@!%z^YU>7wfdqt|f?zC$w@nL!c!K+xfEOANZ1@Nvh ziTP9^Krf_T6A!&@|JiG-c596(NUq8a*M*cOcn7WI9bLS!_UgMROl%dQwZTO+nq9Ir zL8!R=cd&xmk^y00Nten*8VhgwTrm!^0__=fmf!LhYhkemgrQ!6G{t$S`cJRX%6dp) zut-cK9@FPiJSi|#%B$kniv}`u>k7t;L8a%^ *=Sa(z z-JMdi1L9RYc)jIP`y>pL*B~VrRrM28+2RiCgGQH~lL^8x^J_{)^4H-8L=wP`LOu*U z$*5wVip|;Nixi+fYyhiNJ1X1sC2%S~+j!b`BJgvNSgdHM&aX B<|k$ z8xLBQT}3NI)=!kMBN)d35n}_$m*5PzGS%Q;3y<=@%Ve=<13OO2lq8HIq0Zm)U{L;H zWls3>Mb5}BxBn*@!lm-hOt9PKp*8iMKLz0*|3KmlQnoT8Z@)8tfWjz%64Mk&W%Rlt zXaI7?7;c!c-^6`~-I+La1)08N&S@#%Jff{FUBAPgkqnpu;aV2p^lXlV`#~%QGHtAO zQ@zYDi=QE!N{Fm#pU60RtP<0=22N?=DsY6W1C%;47p7=e0Nx&}gi1lz`Jl3~@iA4; z+ z_ka zkQs|F*gJ*hh9)&52!Z$j%T(#Wq!tGPUgI$srWg~8{(%<(wNLq(P$i1ylqI%KSaE<@ zBu!a0_7EMxeHphqJ^=mis3_L1LGnZPlxrB21 |gDTbkQWw z&%ilk&|LBZj1t$bp%GOcRCYn-O+>CnL)c)({P&zaZ?&`nzC1Jq>0iyWeEEvIV~VfH za#CJ+X_8r}6va=g|JlpYD$n5sb%t-J=j+yo!Ec!*oURpH$3g8x9SmIe%_IKTg^#L0 zPbn?sKD>^|yy({Zag2oVm?kP@{cr<{$1L$VVPyb}3-JaUih=JpQIf4_Wo26&QU>Wf zo#_`%&R^?lW6qYf*X#X$lL;H`a{a!;xl(8-3evySZTekvt_>;dgD?Y?gp1;emBns4 zk699}$%ou-6C@HbW~r(|5wa`OR(??q2zmT$xvBbAJR0kR%~z-^gE~qlsGSw!7lt() z3(&L5L|KrH%L9u)sELf0I|x=0?9>^3iG$pT2l7)~a_@RnO9s%s4)UHR=CF{%czg+O zvis37S8GJBpTGaP?;6JCbVE^)X^ZEa5<)uLT6;0LPJ<2lKn`AYEl#%Bw(C##6R0?$ ziXw}e4Y-Y+y&YI)gd&PnGY6GN*B2z{Ixq1CPFR9?0kVY_3rfF fEc2BUSfMNKG3i%+Yy_bm9c~sEM5>TQh^gHxrw9)+Z6BpEb-I@2b^~f zirK3CeYF*&e^>5`(dBnFDPIRFrQ0H$B Ji3-9X&mqdlrk@_8*&t+= z5c;{V7LcrXXLcNg5ZNlY{6HoD%JXeI1zTZKIzBxuh!_KjGE)Uh-HE3VAg$dJNsdQT zp2w~6GH%(%FnCh1NA>ynCHEc6S2b|ur1?^gENdWBP}R^2VKl_>j`{DIvs!lnua<(e z&}zw?`5}Z!c#B78KY@*`Rgs}qC=wHOEF7?zh9>+lUrGj8wSs24yn~dXt8YW%*Q`}S z{mQ*mbiiI9T#Z{ V3PV*Z>tGZ^%2f2l+L|gRz8S1M#T^6BPrL|v7K!PU zcl5|$p!o<(zFBFE(@!wj5wC#YY#*gAD5+NLF}u uC}#su$SRu})0is?P(7Ly4U?*REOS!r9JZp@d5*T; z#@e$o(q4mog|5Ha+E;1=(YQ q%13hGB@8fd(jz3`Bke(uXQjRgI6WH&brl Ay|(vAgbD zl$vH&H+ck5mgkSc3`KKFki`_Z$uPGZ2^p#}-!zN44H0(hE!ycD7l2DbSmE7qg++n2 z!f7@E87gG=@bRcC6ccpzSr~STG7lKvuqP!;>_8wD24rcK_zpIpN`nw%*Y&D5P0-2v zRe(fc#ZWYMfoj#b3Pcx1i(avy^*{E)(pMg^+n=uN+jm!5L8dL9^Y G;S7EUMHp=9h@g~H$>Rj!=Hx+gfKPL>&B2p!gFiZY819iHE%C$1kD zFQsv~Q>FUATPx2ArOZkk+i=|xX)lH>i_$^3X3}7!T;0aWS}9sIs$*`WG%i>vno&68 z3Gz}q=wP#CYv8O?K@y?YiyyiD!1FI13s&LpS4u$+`q9N(KDlDqubPy$5EtKZNZvv~ z+LZ1q7^JO*g=px;nJF{Y#-kP~9uhrr4oQ_UFy5&ODDfVtYO`J8Gr-2&mnELq^tM=t z1wpxuskjFOVht8*E2}K5<`)Ip2!-W%5BdtkR3r;nWLQBeB@fcW&cMM0;}|RE-IG^D zNSS{A4aRg9!03GnPiz!6*>T>V&w6~kO0rT4GJVl`r>Bt4ut_>yHX<}7vQ)+ys*)?r zR BkTO@Uz9p`|BXwfec`wrL#}&%%UJzGQSX$aNt FDZIr15QPg zo61>z7p^DJ#9MS!;wr{V>Sa2GnJq}Y&w?6CTQ3FAwo!_`zEnL3%=69 `;87hU0^W!}XtU$N$H02Ab!~>bCDo6!<- fa+-@?+zep$AphCp8Fek;VbJRM#M(OI{~-UGc| zM`0ixlFe^aL5bsmx_V`t^Xrl+K6#CQ^Y$Whz-LCX*zV0^8*aJjYv)a!_0)KjWZWKP z+M?OVr4%nvmejB<>cEO%<~8UpIm;?3r9j+-D^ONh4pEd<4#Rq(if#odaszO*V$j!u zv?-5?@d`sdBg|NjRQBc78^1gp|K Eo6c^__?rbPc0B~r0eDA;@s#7rnY zdw`;$$50qor#%$hE8a?5CJPb0QU}@+@^8PJn7Rnqj!fyS#dnmxn8NJ7(O< zLF4w7 w$@$VNNbirk-tsuuP`TT@?o5$`=DZR!f*f7|ng?Nkt z8I`X3r-5{<^Gh-QhViNn4A0J%++#5#5DQG(+Di{0eyO}q9Uth%DrwgGhqoU-Camf@ zw7Va>FMRZ_tE#JvG=wbv1o}<7vg~qJ`pO;44rb%f@gkrsmGB6lV_f(t0eM#*sPfVT z<*PcltdP0bGXLGu?)Vk)aw)`K?>BFG^`E@{3%h-A`5+}3(}T=deD0B>qv=ZmVTAP* zD{SiV;fdN!LUo)qJcbdGiGiSI(*`}_*l&RaYntpEL<5SogxgBsV3A>Kr(6y~2^~8r zD@0)BV+e2Ga;NawT@N42Xbt@R$Cg|bmj2 #~-iX(z3o-Nh ztwP8Tk#$1BvaBa+6v?*UXLL&)*S;!eh4&xmd{p (Xt;y z<5zr=RQDR>rU%dpir#1S&M(gb(SzR)VqvkgGRyjDb@Au>zIW3%54s6upa+?L=j{EP z5dJR(<+kkFvIuNom6-voiPneC58vUTs6HEOWc6};H>`^n9n5-7r3_>C6PU8;avJQx z9Ufb9J>>uy4hZZZW&7HH|44Yvrfu=_D*yS-A0G~XbNlB6)l^rt*7y1%fq{7(RNh)4 zWQuk3m>eV%G7vMiTMmeT6oW^s?i&L!bP6AFZrGDAr9R-;kR(v&CtiuoU7pAO3;yE5 z?{yu>Kn0n$X!gIP6lT_PA%U+7!nudQCZD^!hM(xMlXU~$te$z>&j0`*07*naR4?tH ztRIdC5{)J4HF!CHZ%{u0T3ruc*kqO{uvk1=&$Uxd4x4PS(JCuP|BFwrSQhrZ>1; 7Myp>i5v%)Cuf-UG^qI%C*;cy4}< zeicHPyYMeBeBVkd$c!cDZ85r{c_4%^kt_gfuVs~t#o$C5`t9ocbh!b^yI5<{0L=Pk zxYf}hV}fV(c&};4!P83FC>BBH1is^S=y`J^YkKR9aVKyGD$!oopT^KteXv@O>_ArJ zv08P_%Y^g>s=S7a9zYIoUbal6?gtTrt6pnI22l02n`&&c0bRxpAvKn<^g?`glPyMe zxZ$01p71uk(}PS~blx#3HD6$52PlL=FSdWk%hMC%Vx4$r2`LDEyfF; z;X}x{$yjCity>2Vgo8VLyJqjmQ-A<^v203VSPHV|b*BP*Q@p1GU(s!jhp4c7S{tjp zUn;kee*nxHRMX-uj<~%*0-*f3!pOR#OKDU;NSBwyti8S3l!NLJVlN!K;Jp|A<4P&W z-gnNvHKwp Kjh1XtD=_gyi`939{$WR4}|}Z@>jBtj9=C!p3HA zE!TxAcnM|ld2jTC`Uc^a>1Pb|4CDRfp4XqIshWBNi@Fc!%lGDpIRu`Jl59zWno!5G zR_g0e{-R*2^?0`Iy(5uaL#jNGe|}OohUbTLa0v0Xg@1YBUgK7feeS$qr{!VAFQ_33 z`EuJ?*B{hEpmFsRsESrP@9b021ChmQe{S=N0D;KmGvlQ~lKNt2QX=i4Eha30tHb(m zkc-3(BoXa_4a DwN0Ubg9r z3=6SSsyYHHdNoALPo%Lt9KaqQpqg5LFQf?*;-B1lz=ijDUbIr2>37UNeKe&rR1H;G zKTl3I^_#4yiZ=vbRxrvu8G~^{gq6KFSe2|`ITkt~rWUcmhLy<%_b>?;PIcXYk`Km0 zmv%HBM`O!jDM*G`<&V|r^89wE9D|~+dj$w&i9i)RgJnnEK_`R)m-oO)AmXIZ;#G10 ziUzThC%hFogZn}XF|ZONe_^Cw<@=YPse(io_D#Lx+@FV#UcXZP1Vxb*p{}r@PO@p^ zuQ$Z2ebNW0BL* zf`tWH*hKTjsZEm%tcA5#4}QisVv2CV-OfxygHWs zLz5He5)lSU*p!lKNF||}&2J#A@y^dQkfGM7ycv18Y;jer2nRsh@4+Zs3m$9!x>*m} zFIJ{De!O?#!56*3Q$qE#>37cFeY8mnYVT1t#NL!=X;Ks 3eR}Qm`V==GM5Xgh4XMeBEggB4L7rL1dwWvT|F{*%#v5-Z`9$$M?MURIGau zPuA)v)@Rup4K;jKc?1lck-EjWpd-J5EEOETt~yW(4QT+(O_j)-&Jvlo3Yu|&s1wt6 zy`9Q<)vP{3^Y=n;(t?>6E<}Z>JjmX6%)U6L^fC631BBU!LE6W8>`9&1ki=5^?aJSS zb?#s$NJ;Y7^>v^)r1eDVVGdlemA#h6t;e%?LH>Q~JBLH_whDq4nf_JWvI-$gvaB;+ z wQ$cRQwHa(aIU0Kq-11cb=?{=Fs*6%?81XD z`uIQvnYM8DJt?HOS_R2)ML?~`DoOc5?Z 8)Sp9@i1N`)K s#qoPJjDyyptnkh;@wo@nu~P4ht&}*K0wB(d%zIx8EB}_=_hy0ylCf61$p<<+1ozzTzD`viPIFM z7$RiGco{*kby<}Lo5lE-9*7!Pnwk9*-aiE^!hZ3(&=8kiMUiZjt9}qAP`ZqQ4F_0Y zHzo=p4AX;%^(E{FNn?|<%Hlt$OdU7S#&^2CR_Ii)<~BbC8{p;4vI2MXgMd6K#bB+s z7E~R+qWB4J7N4jKLX6_Jqr{LVq>Z+}ZRWWT)2Iq!Oro^*k zk|GaD8>2nPSO*3E0dX){Zi`nLLyCpSkB3ZqwGo 2!d$p8+$?v~@nXW*iM3 z=(c@^6N60t!71gn&i?%B^Ruqc?z4`k)Q$RHKZwO$U>rEQC~!}SjH47-yxN`|qiIAe zwnABy0{58=fs#K)>`=7mu$3IpkBq$Uj=#KcuCE|>%)T-;>4P*;^>8ZjfZ7)E4*miV zrct3`J9!h>cj7{CA;$W!b?o@8oLxsS$LV=;Aexauby5t9nlyY$c~lXP{`7{cAg0^T zlzDg_! -dS-zU6 UZp= zD;FMo@rQf`S$NJ*LkMpaTwg4{m{~)c6`@j=!PMj1#+@;|5Lz$ZTV}&RxeCT))&`%$ z%7WA(&DFVBOubKW{QU%M$JBx8rX6IJZXJ>b+4BddD4b#83R`8RG{v(+B|siT-xpAk z5dB!A$z?vuQQ!;|>m^>zo*&ZgiVragrxJ)A9fXLNbd~w4oL`Oo=fBdQpVyGC-J#gm> s2M&rdm@2D2Mb$VQ!xV zwM+#fGCa(_y2ueQX)GK7J(b9c+2pVHV~`;#h_&=y78~O+nVt__6!`&0OqXQnV7H>+ zjWy5PCmvbQgI6?}A382pP~}U?42|Pb-k#=#=czU@&x{O4jOkSiXI}ifY(C1LX?M&% zBsJ-)yr~|xP?n-jM9K5Do2dH<;J6@H;`VI-1hV}o=;_3oD~!X7w)I&!r`Bo$>tVCV z94w05v+u@$9tFZ$p#H3e3b9ys2fP!WczDud^z_UEL9G%9G TSG97iXaaEZ z?ntaKDp#th%)j{!ys1i8^tvTTAiskytiakj@}?ub-k}R-e&%YWAbT%7r{C;c_k((v z8t}fv8QKDfN7hwsRiT*)#w$bY^%E$_XLBgD^MDCZU$u!U#dm)BywHsu1K`}qQdTZZ zQe4CGAZ?J23gR(T3KIEVgAAImeL9gy7GKjpctR5RcCl4bAV~XQ_j)}2IE)o-lB_C9 zt>wotnD8Sn9u6sf<&O7Xbc9lnsSD2eRZ8i#TH8d25q9urDvRLv6KJ|s4y(2h=KUO4 z{02&4gH7c 0 hT)lce`05Y+kp3*C|bOuwv5^7 z6n}lk`!8xQENksdoBw#Gc}N35eQaVO^fjN1Iw+CY)fNjiF^WAYW=tlh4_QMWyhI?I z$O>y(X)D&EE4M*VqCJcfljv$>9sn53vEOeZo>i>huoPtS_fIZsm%w|VmACm=)8@=^ zm;$8anJuo=)xmiFbn86Ls#Qz{UBTN^P$>iWc0!$B{)h?-DNM$g*u=5&B_t})KS=W) zo!f-o#O?a|koFr>7o0OarF4Tww^}MtMHhwKa078M>pHuNR-=3d@=9eb$_Hj)@R;NQ zG$4BeWV=d0?~c`>Y)tt(UPGM;XlpxrFc|q)G2FWEkn$kk@3UC-9)Yz`?I`Uba~$GV zC(|6I4FEkx8K9GPFSY~r$X4@KUVjW)9?y^F# fmu0 EO}8e?x`yRJ_Wb@SGIuorxqk~a zM4y>W#zFFy&w#lbUX!*`Bw*#d%xm*-``K22!F1U#Lpq3ok)$n+)jA)zcGb6@a%Kdt z^GQI%TanR9p87?nF?`~V_g#E(QINC0oSM)ECG8(C2ruVM_)#_WlTdqB0TlwQG#>#e zlIc6H`w0jqfGg>61*B|>4raO$2|Y0M_9U$Z;x0wqrH8>O+XQzXLb&Z+!-+vAfA8du zyhI(}DX8aN{>DbhmZx{e94huuj%>jDO D0v2%s30i^xfmc*$aq0% zVG(=5M={2$?s)&jM;3^6){>OsJJ^G?vvX)%*t2dI50gisGr~+YOcWfm=O~z_3hdCW zR{aFx;?Y_lwQB>_uBIlZeE{5t7C>!Kpsg3YAo`wRd5~5?Y)n^hR2L*>>szd7_c}rR zQPJJ=1Mh=GlLLuam>s#QEqs;+gj6WZ0%37?$+qhjTVoEv{yXc0HOAPx>yGzdv>U}B zkEf>Df(l{kIx2w)>Ouy_^!|NP$Q*!D3yiZgDRAzjIJG-AK&!I!nvL>rAuntjD=@HB zv{ajnGVWOLswNJQGDR=gKkWJMI;TF-Rrtx|@13OMI_zvTH|bO0tl%rLJt`(M0t0Uy z&X+Rei86wKB&*jCLJHA&0}Y}T_3n972dDBS#jkj=CkKmCm5t#7&tJhTT{NkTbT2+} z=ld_-GVXWJxm*45$ 14;8ndOO(icjegUdYF<)dE z0q&vEQ)*=bXz>JH7KyBrAq%`q+w2hhtRX`zb_udFTgt&gN|!Ns=ZEvvQk1Q&ia9|+ zkfAc(Lv6u;U|bAn* 1Fe4p8D2y%078Ol+*~G2mj0NYueMPfk z>A=mv>nsV&^Urk93U%_;K6wc#O-~wZS#ji0=Yxz198lg2?a{1z&z7)!rozx!osphY z-IYZv^O)jUYiVK=$@7{2?qPcn^D48d%sp>X)g+}LkZb@OVJEi3JQ7=4Q|423{jmgy zRb)72&X4!6f@heUK`K*-0*r_A>FM@rj5};@#TC+Ge0p(Y*En_I?DwY8(QiUV0hlaZ zOM^vloxJ wu#)a#f%!Iyj%)M1 zOW>4s2Gh p}2>oAd|m)QklQ#q~L4vcup4E z6bM?zOTi7wiJ8mWY|*D!XJ$+6Fyh((R_XK8Rl-oR;Ae;xF{Ayv4Wn4LyfPFQoZt`R z1$__lrKU+oVtxbNPF44!B4gB6#C>9m1ddpq9rjVd1?!@;AaiVBgGYix7C*zkcirlB zVcPa@X x{R^`ne&&gA_apa(8-I6qSn}{M^db%1Lr)~$m|_N9 ze#Ic9>-->|ppqCVibu4fZ*w6ftDv==98JJ@`&R8@{BmDGzSA`6z;X8z;AVjEspl%M zo3qu~_3K;qP`hQvwSq_tP&Pv~H%YFBzRz$&1`n^=c *Vjveiy6KIwfPR`jEX ze-X}I`i=0rrytFZa}1^`+jtAT$0|%M?hXw)3bT_DM_=O078+#?ED?WVVQRc4?tR;t z^FxSxuuMCPRSz@F60)#lEd+w)Nz~Ps#vQYwft5kNx=6jNo6PAmc$Hm9A?&=>Ys0y3 z`|Fi{C*boScQ2?%{?~I)hZ7fmCEWe!ebQ9a3IODxScvm4)cH~3w-z9Eei&?Z^#duE zs$$j*V@Vd25|&`Rt**xqZjXD A@I>MT2PV;9-L&+U3d*k$YWuxbtIM>}jEZhiQ+E3^1mVJE`Ja5yXv z`k1xnfLv6a*C5K;i**OQJ4W|0sGI81E`ze%AE(Yg>%k_a?FQvFY_+8IisDwq_*XPN zen~M^ YF^=PM}jPmSPmwIaNPfMKsex4tM|gp7n2aL$+cW_ z-yLDjQpq)ISe+%vjbjH0vxQ|?9f9x~`R?ilNr%cu64nB@TG`^`amsCHJsncoxaeVV z0oVp9Wf!Eqg^+@GQV;0qW|haxpk}o4c!gYsWE5W *F-Jbo5+;ZTB7>{K3*$9B#nABvSYXhQ3}ot8 zx>0FPFZP~^d*6E2iWJg_Ixt|eP?K@6y8gwmeGcWs-pB;u;3$i`RQ{m5?%(zZGs;Tg z+Nr0m&vUFLE$rt>W?XY>)n3bo>C|?)Q)ARZsR60I%fHffSp(r&(GV_(r4lH=aJx*^ z#J(|%W(7%2RuEGLpy;POzcS6S@5`zuZ`lX$opW$opcmMo(t(nB9b?x{J!QRutVIQx z{+)ass?B6mRBGj+vj?P MZfiXq qaY9gh67}4xwMXl2Z6zd;HJ!5Nj DoZ zqz2u !1gJ{ib(MEro|9L~XOU8P z)u!8oFZ|j1Qj;~MBmGj7qi+0%aQ`14h3LHN{Di`lYnXhN3gMQTyP{Of`P+->iU3gQ zOI=FR^&%mlf{R?oUcc1j)-&g)l=e^z74>y{x8iBsRHV|sas_+U^V&)X=e=J7C|VJ9 z2CM2vShUtEg}IuN6s5m8J8!vTIB(a#SznJeWG(3{#|gK8IsCXSR_rS8uobgl)bPcv zh|Y__9lQ6uexq+I*EN45U7^+Mppo&S4HAQ&ixqD@^E*w`94JC&`nkDn6IIiXH~hjc z-5>0plMU$5DLJ=`VD%<$ipP5O5AT)za`(3!6yCnRE^8=i(uY;&-u3lx|5J|?WNSL$ zR{H$9`pyY@$+fT=S_4|ad)1IcvUdd=o~JCJ?qkme{hB!CmNUPUQaaM@2l3#OTObHn zNznw*)7|CzDww7RsQN(w@<~Qt7_F-D3q0pLwtiihw!>Rr=t fv98 z8}7fG1M;!2^r75%M?VP3KU93XEwLIqgD@9aanf?FxS48R6$Y~$^9L(56hr)SoO0`| zIiZOsSlEJ^#UjfEU!sP>HPbir>kbeCu>-8i4L~VYp`U ggpkFvD#?U56 znR9on53ipxw*(P@V<#JM`+LqEr$`R|*re~Apl)T!>&IIS%S555v#Xe|^ZZ~6%w9Ux z5!FoL(hk{vfY#9GljC9g-ba)l4T1Fe$*nRTRgCkJ^TPu~xG(AT_V{?;;`wpPyfZ%$ zLi&uifl4t k;+ zLfkd(ciXvJJ-K38d-bS}HHzSxyyQdXI~6B8_VW+|OL%LuGjqm`gO^!@UlJZ0`JR zH EV`6h)~J;bNqu1Ng_`;H;Se$lT! u_?U24blIk~p_+49kP`AyzIFRWqoHua%M%iN#m}Yu9)vuz+-q zN*f_S8T0(WyI=yiy7pD9pVJRwu2(h5V0C`&cEFp${0(5il=VAT)rRoI;=?Z8k`!b~ z3h5p4(h{+NuE((NDCf=R9m#*Ofqe}v&7q1rWeYTj@gfh5(qF9p*a7{3*A-x3Y7_!h z-1;xBJ|NoCK!#x{NDHw%=j-5PH 8uie=+pBK;he4QD?`F%kTRK=;$4dlza+o@V9HIizMMijLZi-dy2eOlnbbFx z(6ks|+Hw(loD6|v5lWw|_fg}Sc|mZM7o4xM9NbSpnnem-{?D#}G!8%K^b<&JKv`k2 zL{9Bm3$cb2q_+w}F_*Ixo;_LAaWSwF5ItC@*R0 zve0tVM44zx;r0XPSf{f}|DN=% pDrj4VR#U$T%~Ncro-E#Ez!D!htpAb%JjA}UHKT`?q!86I&x+@Fty`# zQ|~H%>53P%U?`5r^FRjus+)7#p*HBvSp0#{<(GKA`_|dp{&B^!hbk+~7rNE;RHDI- z0Nb0NojMtNAp`C>3pU$V%yi;gOQo6@w_EFw$ %AA= z#xL-SH(9%^W#T4ryW3`7l3xSe|1;&LS-(mly;f6!K2t>kEE6~R4Yg;;S)0X}>dS1E zAW)(z(JBZB(Pb K@Q`EH-&HTs6OE?_ti50%@9>7&?*<5JiSL<-9Sp9M}0lK&0;{)fK(vEYRp`)RULa z@kbxNrSR)TM_jfe?MhaV8)seBgywM6;5xf*sxE1#Xx$E+>MBj=BSE^U9E56=ssck@ z=FE7t%t7D;ZeaPP^CR@d?XTMbAi>pTd2r2q?zJ_=M=ls<3_?pPNk8n=Btv5pf0hNR zbj&eq6dRD;QmGL#XeI`dm )k;C8Ejas?%b$Mkem4l`6%{S6B#EqnuEojPXRn{cCCEl=s{;?{ zpM68Dkxm-15g)*s)Z^B!8Lgy(1uT1T(gVDZ$H<8_??bF1vRG A|xbf z>Yg7;cd_=INaVet$%!|>EIld&?vKhN0U{tnik=Zyz-*;+DP1eiZQCuoT$8pJgF$Fy zgWiU(T6oySzf%g*|Hqy;e)^{|gg0upO1=wQDGdjpEQOl7N_LZa=@`aQx(ZgwR1s3C zH5Y12HGaAInliXCV_I!#GqIl`|BOi;hBjsXEE8V7BwN{GDu^V&bY9AXRmIH10^HyM zMN)Zw6cl9yY%>yDERg|b7RzA?^=|G( 2EbhW_paZ{O8gR=Ctc1B4SMp3{|-S&cfDFft9kh zKf_YFyNg*GtFWZcE q&x;- zIU_A& u@m7RGf}^tCuH)Qm<73C{FrU=U0ST!C-YLX2KPrqpNVq&!{+r# eD@^R02cV|`e*^WZh-4!2*J1}!CyrZpOC zffY1^JH4`{mmEh`xX8P1j@Roa=$IP`z=A&?jt80a&Eu=<{>gie-D{!YhcW*8O&27< zolr^xQ`PYYddBBpT-?B*Ud%llt#{9ruFV>lu*EUkDc5Bz#TcfIHyzo&pZ{
cgVJXP&-{^Y~Q^szCXKQV%^CQhC(Wo(kHEg_H zkmn)8ER3MpE)pL%w~^ pSR!`41ygd3P(DnT0#t0Lz#`cf zOEK4D>3#y^gXJW&{y7R)L69=H+lLf`O#0?=E71>PDi1p9s951zS*_u!- $)5|YXfK$U mlAgt2-zEnlNKFz*}{Pe(*NaN zKRo^CDW%tQNmcPxMNCymIR>XLoKgWjQX-CpE(-xLR=@WSX79pPlt^U!%FnSphH!hm z$z;~Z0vYdvOuEv2yjcX?YdPr!e||ybeOBcM46!hiZPqQV71GLFS>@`23bG=OK`X{U z12HuJ5_IH`LPaqa7{b -_R(Bpkpl!(v=xOmQUs$)ZCqy>DC!(*Mw2KRo@`l+vD}-TGP> zQi^tSdEIqzSG!OF_!XI@AazGDuHu6_xVJ7588^KAT3K7fukDb!wu#3qk3&mF2Be@0 zyT8!+7sIe(klnxj$@)2J0<=k3*eU%Rb-XxeuW^rg11e`lis5<-tqa0fF&mZ-z=jGK z*jI*)zW^uh#2RY$3id&BLJYSpKH~DdyiIi>R{w*0{_yl;LTbK{*U)i&i oNmASeDZ~-Y`7~ z#{yLhq+zFxJ6cQH^*Rgp{PGXUP$Dm&hypn4YQMp2puuIfijLT!f@_5 %d!x}PC04+F$btA=w_-2>T-RaU1o4B%QkfkDd*Hv#az4_86JaG02b4Kv)j zj*hoJKV`{ODTESe!1Rn7pnaNpiD&~6dc*1DlLz>Xf=TgF>zPZTs_xgIPs 8; 3?dI*E9EE^tF-YP+}M}f zuyo~bt2m+4?NY_ChCiqjm9;3ptlYc> )`Sx`sPR>_s9dW_-c`yH{}n`gyY%_=EK|4WmvJ@tqX(wD1N$SR=o*$%WF ztkrZFm@6qCtc |@CDfzcB#=IHt7Ub5V|orbFB?dcQqY*RDeC;x z0Tz>s!j4ldITB4H>)SfzS^3;YdLu{PdE}*64LT4u^j#l1cFE@_{KsSW- =~*TG4llineFSsdPFrVRncr5RnYKd YK?>EtO2|vSwdssQ3l;2#)z}U0b`^~O9@BI2N?DoOstEC|QFYk5zsUL2d zbg5Dhqb qrB_8PK#6@{zg3Bl8b7~%;LBt+H( zY0&nAh8V!|{a0_kP59!}kA|0RxXDT>N&CXg8$KKEf9g@SKpPL?pcPqQ2@9C47tgWC zkEd*eA^g#;iE80Vt+-ejQ%JdNe$K#T9|9O6=A9`z1$RcG*~mFs29T53u*mvnGx{ zyW+kS(+-dov;-*^3NlMVSk@>-ZRy4OXu2-{oDQ1fi~+5lRVKe3pe}LF-dh+Rm54II z1`8VF7r!#p%lzi~Ys >gDI58j*mA@Jfi z71Rs4lDE&f+?nAIL?K06$yln;ysJ7w2Qm6tJb=>=0&!BUfGAHzf 4V4bPK|y*{q0`K!cCuiAXuaPm729usaYedrhA+$D3vZ=ZTt z-8*0{8! v_ zpc@$&%&vEhrD)uugci7omCtiTic;5|*~R%@BcD&*b75gtjoI@AciZj_VaBU>3A=3j zy0GoWTeLrW_~|FYj~@O-xbe3?4vQcBnYycs4oz_n%2SuU=jr3zfUb7mB}hh1jo$uH z&0kbi^U2t@(9w6U$HMc6q8$fTqr#5e4+0h#NuHb=dTi5|#n;Z8dHGXg3Vm7kcs|#D zX3uL+IX$Ix24$(L K~B>P@|1srcQ>68~)3@N(^0w z5tY(HQJ0|b`VAY0j*yu!nl%XyTTR%07FsmLnh7FHPm0+JoMi)R_aaBlo)8!wWyLWL zgF-_L%F6U){ds_VenJUL9FTugGmHv^@fdVIRw>vR6;c47FGd+vu*?7yF2;EJ;-fA< zYrH}~t{8*{+xzBOTaGSU{;Q@*TeM#sSlMgj&BLrLu`n1PmeVJ0g3LO `XCGf93X;9Z zX@8%Z(My!>7XUa223aeuETK6h$+^%G8tbE!4FVk%j5~A)!!ApOf|wKwi^5lJCcRe= z;uTvjWV7}N7sXWOku5&YR!dXcD9qf0&nK@oF#ki`U-^_yt#ix*f@$HVdXCyo+Ye%E zpGqAST5jat`21-7MM;gpRUX4;#x=&Q*9f&)v`xKU{K%psFBdj;99ptc9;83s!D;Tu z@2~ywqL9+AxB!7$@)8+88HMlifGd5V_g!aJO+P`guuzPotukirtJ*PQ#B|9KS~3=7 z!+c?!Q46%aB--cu`8=!#GK!toZ_3jxmiFGRB$y_94 oaGLjzcf_BP*>S{cldb z?zBG(&FI3mp^C1}DeP7y1m4Ct%mi%=9}>MJMG2EZD1@i+|Hi5g66V@7)DQ#6E39cK zmLF~wu?ckxt(;TAxvBL#lq)H2=ao6&2{0Mtd1`@g*cK~wN_8O=V0mN~O%Q8iQbr9J zzp#Px@ Bf74Z>U0YpCP5 zo8s^; pD18`iU^L5=M1qWbb zAk}GVl>!E?2oxv9KvpdF;ujVlb;T;x_^gr#=|6biYiDi!^yu=RHlf)Dt$rc3C2&Q~ z-J$QSg~mIsG;TLi?0JpWit0Q~#@Yg{WE3kp;sS6^+RBTEv5)r-tP04%L1FNm=aff4 zGC_M4QwCxP3tX3-e>OQ{%Gev38!;s`0Hve*#7szMVKCJ|VR%@dpV|P|GNTtFm^kqK z#NsmffqAZ!(jyzjjo-BJ=!@G|ov-YlRaTJJi+um&BU6*URF!vtrdO7`$e|Sf>64}a zl{QM{Q`(Q3#w*M6C=X)WOfl~Pu)*22$^#W16CYnhT0CU2jA*Ir%7dCYv%<@YVHqz+ zDLj^n;}4Go>MZps*2Pp6ayU}lxl{!>udOg~q?hokm`|H8DbFWQjr+%j#NtNswI-RI zo37GPOOC$s%PXrG;;C2ln|br&p5H%Zeh6ujI0wrJA$^e_Ce}Awl(G8>)R%b1XelVw zq9Bk13$leXca)+al94kwA+JiTyae-gDM_`ZWLAm4ubPCgcLSc}VCo{Lh2$F04`LyH zC5X`MrMv@dfaCE=dAl!qz}16ByT+}Yzlm$upL!IxcYf-T2ouAC#YbO0ImQUCYvlxf zwLD1cMXo*VZDGaoyHbcF+U=H!l=m|rn^Dn;D99|Bv`xCS!-Qo;;mjRONH3~>0#c4z zY5jxGbI@MUnSoU}JPzoS;U4TNf28vp*iWGtn(B(ydVb>7$n;2sH7Xb9ZYyu^)U7#e zAX->$@C+8i#wPG+TBecpbNWHr_j{Ca9Z~mK<mKFHU&JqN6VP@ye-${`6`qNPoCJ zzkkxnO_R>aL)XbQ5p~_=rAkIbpLD-XhZPkHGshfqU|#7o%s>e<9H#OdG@92>P<}Tk zBQ9U(xp7s2p>R0^UDoNfiPE+fYoICIG5}8B3ZLG8WCW;8eeCy%>)=@ukd~;>>QR^8 zvrl0P+MZtxi&?I+6|3bPuazQi)EhZv$x)ZhULEDYeOs+@`cP}~_fNhyq_B^o`V4oD zwNKr(S+c2YtC{hF?7EX(73YIsT}o82;)P`x4yxUMl2|xtoAm3tFoG;JUN1y36?=~X z(8s;Mm`s@S-V`0s<`qfoCP!NDwd_x}7qVC+2~4mn0~+W9 Bc675fb3mO?4FWX;G|$XGHr-$-w&Xffs>M7@URHx$+(@@}L*Q zFd`}C(im)3a%&QA<@uV7^79(%Fd0RN)?pk}c{G?~Rk+w506`P9>-GB{5&qzOY#dZS zzkJigV#;RlEh|9E;Qkf&+tn+?vQVDkB_%@$qj4loUwq^hw+ur$XzPYGRy)of-~H5S zAqBqU6a`z(sw>d-gXio>biEI@1JLiat0yZ{V^*82 d=_nb|=jRDB48Yb;8lYS%*f8vQ1ZR)fzRBwj zFbOPlK2hZHhW(G(e&0bil#E9q>}Q6qApHkSzv1NVpM7TZ?vUaRk{yQXadH$S$Z+`m zO`s$qT1N_YC2;IR1Y^|!QYp5>S|7?sFmq%(A2GDK$sQ4TmjUf80ZixVJ?eN=U3L^U<=id zhMt;^zt@Wo^wNgA+ bsiMfuKZyM?wdN-baL4XR tZ!pr^_s*j(zj@fo zL1(xo#%;%(bj^t$2r+!MeF>8aFY5P82)vaRQB7ld2|KWg dR>)x zWVno!GmWRACTu_b6|Z4Zv59y>j#*+%y$}ywe9RSJTT?>3#ykj3c=G=}=@U)Ud`9lJ zw~Y?@la_O*n8l|+jn(O_&w?8n%UAfI%1KEa;#A^x1crENg-=}qo7MFqA(0dlgrgy- z;f#1d>61alEW4?biMAia3UpU*Nh^u4QDBcOa8ep~L;Eo)N%<_pG-Kj3?DpQ|3OA_h4b)NB7)@k(_rOD!`6z`W zrGUWQ3S$i|iyA=O&~9m4XgJ21(ctB~qNcW$xgF A`|;^IAOtt|pX6fei2CLdAvgJ_n>Eed3BZd|-ov?}I+qCAHZW(8I-&nUB^ zRV5#U>$EIYmVfaKm4WBjfT|Dj0zt0j{WMO$1r~SWMRWN%H6!P-X!%q1YY${y17NT* zD7Lzr){h3X7?cGQw%mBe!kHI8vo@4tt$Gkz(B$uaYOB!|%`Gv6x7wJa{R{ Ye&MIaruU@AtiW0^M|aYaa;KsBaQASfB}&Wj4v zI9Rk;Gj1TzBpHs5vhbRWxTnt?V{vSu;|_+K2;q!JgNW}Z8*kd1GXHO`_`}*#j^{-| z`VZ|ZNwcE)Zb)fT-f+yC%a)Ku!!iaN7-uIipr3%O@u2KA%Z9yau~ wk*rkjhff{cAPs4d>@FeOndPq*iX zAgle Bdk^nQlnsGxV zBjK}aQi@sxT4mQcjUYvwq=5DyHDgErlAs#1xJVM%+y)s69TpnZ1n*&$7S~wAJwOqB zKJlM6f8!2EudRUGQ-J4HL1;pgzkU3i(I%bH{(Bry2m?zS!&~jA19!FGzF&kYOjYb4 zx1?C8p`DEfgR*%gq6&u{S3IPwb4P;J_P5*Ifp&=0Rj(6(rUlqKEXqYl?1i5&<@*%` zP#Aj5_p=aN7(-kud5*EX!aAWK{Yg&x)`_1;Vf4aMqmX4!F@*KIJZfk*px2_3PO |^`au|L1AOSpIy1Mg!q5R$-mp7pky*3E%joR5ur{_lCBv0GhYahW3fG!&G!~{T zN0b}l7>uI$$D$5Mdf@jn)I_?htD>P&tpQzs`Li}7PGEt&aH$wr-iz_bHCbCVUd31^ z6{J6@J+3)nYO^B!b4tw)Rpl+j9GX_lhoG@`Q7j~#%&i~@8Cp>VT+c}b%6|~&ui%%# zVkGeVos!RhQW5un#8Gf$uHtlsAbbD-2|Y Gl44O;zQttYWOQ3eun0^lMJu{^=FVzZOE8 zfy{~OtWyllIC|2lg$ lkbJu)5Ere}q|f(m7>OHx zU`_OMtg2$H(+bj`T)#8%x^F#oN@&ujLkuHcu8FX{&Hj?x#vDljGTff+ n4SqMTQekMS&tgz6)Wn>b)hk`&ff9W%< z`#~IGww1&Dk+Mb$shBD+zfil%_xEB08kFOM{a~Y(!tY}*{`Hb$uADb4VO|sCtW!aH z*8(Sf>$vSw(_EcW+=qm#Wo=lv4Zg-?6cL-|;A!DqISDqzD&GJ?T#^S>tYGsswrZA4 zJ?CCZ5NlzG83!$z4TCiECA2D+q7a-hW%B}G^+gK0GQoR43!IeNYuq2{@sZpVYs&Q- zZ5$67*3~>~LNQ)29)u>^=l=Hi=J6+ol+I{UD%T2`tx?FRL-0_S;C4i|kao8Lf>?%% zp?|VCwPIW}&+)pp0m3C4b_AoAWTa$|Mf>RKh@Z@iu__oo}6_@u}VTKwcp!nt_z|$P_ zLS2@}c&WsIp+`Ac2A(LhvvoPQe*=o8I}6wVrKma;;T?lqf$Kt`ya6~BRS)KPqlzd{ zE)xbbM4e*1fGEMQ+jywZ*$a9j>F*XD_4(DhD|c-u1wP{i0kLYMp5mmhAAe*D>AaBA zHVS?d>jRj+IChp9@)r798mxUPQlSbBO QZcJxqQ>oEWfPDLoQ<;Zuu`zVgd26tD4uR}fmj?sI2t zo#KC;7g9L755ck`0JW%CpnUKHOVcTp%_nUyir|ZQB=5oytWcKi VuCYVuWwR; zz_r|y3;iH|z@hs##t7)$iy7EzzysR9N_#JYK+e2Z)wx(b0&p<4`1Ok$hK)b9sxPlu z+up)^-V4%$*o92~#&Lf(Iy!oJ3Srj{%3o;LBK(|elW3iR8q>xCt~qa51-4`LgYaan zAnNvCaSWtrrt7b(AEXuZ?(283eGBt764>jTO)NB%=}V@+CN`>j#g OL_JP0o2;JI^0?hgw;ltMf^HED|q<_s)?%!jYo8yG;UP)*^TZC_;_pa8}s$_)HL zrKrl>%P)mI=*~qj{q2 XH6Wr?#K{v=Vl)}rtKAJ>gdCn7YWaQMHUbgoY zEBiLtbxko)e%95wt q{`Rabmo0zdqanrrnNr%Cm?aAx>VO=Dn&}=Dw`Awjaix#_ zx=4TiTk%v@m}yKo5bHU#vgx8Ryi5UZqy&P26Rhz3{48h=Q|zDKc1%j P~knn#j z#`F)Hj%@t7c}INq@l`swb@WRw3W(+H?cQ@|ZMJOm@xN_i{A3Ja2UZj`qSYIlY#S_6 ztdtSVmfWrAE%c4bjg-g;t7q#DJ@2JI6gC4$61`Q|k5WKym5q#muu3>US3?sh0qZp| zZcxt{LVO^m<};gaIdbK^nU_Dcj>`CIP3uLgAhauc-#lyLvWFf&Dy48jO5rudc*3SZ zzJx5jv8bJ1Ln)i%fwII3RDsI#DhBXsY1B6f9T_&Qx|G4dADW}}8tUiz;y#^UsT;sj z3cralp1;`!+ka`^5wo6MEeTx5zx<+C5ZeD^mwbN0Pk!;!L(=Hzr&5e>Xe~P4bnf*d z4Jzhy@jO^)$g5dextmEd_xQ5T3G<~%t-41>_oOSj6$-KHJH^QRcyog|=;yH)&f9gD zw_p8*-9ET{9hdE)Oz$P5AhcWkBFOLmpU2