From 92a7336b963f1057f8ecf16fc255cef39224c82d Mon Sep 17 00:00:00 2001
From: Argo Zhang
!$)|E9S@IA@_!t*{Z!E7^O;?lOyoc)H+G7%QUA2F{5vxSdppbd$_l6XU zC2T-&SkB5mb3f65u8X6JE^*$ip8|x95QDq&`qi~a63~Nl`P z-F0>Kai0CT{J91Y1wevBKtg~+LP9`7K|w;pBE!PMz`&v-BEchLp<`oXp<`m=5&(&C z@yPHoF^TDj$tWnPX{d3C=$YuLn1EE&RR4Sg1PTfY78(`}78Z>P7ZaE2|2sbW0VvRb zOb~1^5K;gr3J4eq$mbvc9{>P>00993{5K##K*7Kv0Z`Cir`R9>u>X7Z_0m75pQ`|P zFc1JJG8ppLgQyWrcb;Z(?+@NwZTrN;*87NOk$y7u^JgY1{cfI^kbN{O*Zuao5HY)z zpr|F2BCqi5BuQXhZ%6AY{kROW44SOCw45^#5Rw&DGv^?uctMjCwZL)$+!s2o*0L0@ zaH#c{UEmZ5bQ`yDK4o7^n1iW?Nc(;^Z=SzJBZ6Z>Z&+-;pl+Mt@|`C$rzl9_TP2|z zW6glfIJO%MF5XU-LIG?|#mRse?j { Q=1yuWK2+`BRqC4U)WOEP{jTZro7!*Z zfXACg&NTOWl-Xz8%?MS9j+Fw15HI2pkR3oG%*QL_<7`2tbGF%VsMRC0N=l)#X^yCy zcbWce?>IIClqn)g=k)s(gu%syV!No>E4F0|8W-;D94%BC=*ncL02-UWW)3e=)t+*u zmdYQ# o0s`N(8I3 zdHcr10{xL_N8)8?7_N>giIdjP?Ru~SIk5#++BK<^L>g2cWj(qHMPt9vOk-ja*a>!5 zHdE|^!xM{UT*(S(IkYR3O1L93t4bSPs$9osQP9o@B~ubChmZ$~Oq`ALU0CJ-s;=*~ zBfuLyzPmqaR`p`P#?4!2b^6G5_s1M^Fk-~jHjKen#T)00$&>jv`qo3{Ss*X?n&$bd z4o|&x7u{Gh!jvYaT9e1@9Cb`kZ>=&ll6WS4 mlo$V?!ORw>l;cfp z+w+68pHHRoA_@rvxO6Yr3rgpU%`bAYcyIb49NG0~F2UF5UnG#`adU4ssFJ4r@wU;w zMEdF#T4VqSI4B4h82DGq{M%2U01z;62ozLgG!k@TQb-JDVKNq0Hgcw~_JRI-0|Wvz z;+wJiZ8HR-SrRwy90dgh$-#U}eLS***s3g#?pEHj9O4Y?4YRQwBaV|ZlPxhJ?4JZc zq7!Dye2Mn)$Us_Tr;~4V^Hh%Ikes`tT%D3Z1Da$SJE3|VaSEBXI4+gS;CYtIuW(i? z-sektW^N(cLBqeegPjHb^$m|nQ0rl4&%6x{5AO{ROTrbHk0khZm$=%JzicU$*6MI$ znYpO$9C>0MzG;AvPZp_b>k84_Uu~LP`A-1tX2(jC)3ABh zoMZ9bZ3jjG+gv)6ZQ=wm)-9O!^d|jsf>9ccu~~-Ka7qh7md|Y+w%ll5c7%J$9wfy; za823ZUPxyFAL2f}{LMGJrNFS~$mj3dv+{zc2Gc6sjJ}V^xHQVSQR@*%=*|**5q(e= zIDPvsA%lAT84SwV5p^=B1uke$QOn6E`ze3&s9`Hj`05RIDFm&?M1<-5jq-6hC@{pP zEDu5Pa*W0eKD;&N7P d zd~3DB=>Al}x49Q^-#(HnkSB80_OhQYHy`L{Q;r;w#}}lv(5)BrX>7yOU8UDd#oG`> zN)i3`N)V>EiTZ&lK@j&d2VS}>98+h xKFVwXK|Y%t(qJw&v7W%VGM1wUEM+*iIK5s<(8|RV~dkhs>6| zN9Fjp2Er5lX40Paw`Q{wkI`MT>u3rjv&W6#ZR7SqQhGqQaqDnOl@REna@?OL;ZXJM zD&oiNWG{wE9JXp!DcEswm+ynuQ@?k~ Nr_I!CWA-D2DR z5RS^(6xyz&bJ>aL c3-oEm)?%=Yzkn#0kBsSfG~?zO*#wUH$G?=_R>hmpW%`9!Lin>$iEk)@9pFJ CE*>f=m z1=Afmg~4_7$UWR>bF5(L>iU!qy{}d6Bz^*vl)Ve`bk#)!7{29N&i}$9J?Z{s_2}5( z&xvI>fj~ZGb^(cPLdsouhHl2z{LRmC_s~}(`9<68Lxa-poLA^LIx%7O<70X*LM1G% zAU!NAcMaVbWt>Daxhu_oyDGOo>?XFLCsei`p~SC^LyGr@9*b}E&PGS{Ct#{mWXIg8 zf!6)eSKr){R50ttJ@&iR3rjQKUa6-|me1Jag@vOtW}MIKJZc4)RMoN M=O2UjrtR&1t`tN}Fnj(TAR=%-v zggnP(B=W&*H`H(3=pV7~DBC?^6?pk}68qX*xZz78=j$=c8R7+=d||h6${R>7UJ{2k z@2DJ^a=|1K |(_STUF-K6DmqXvpne8*_oEVeq9GgGGZi;?ht09 z{(eJGJkJk`r^ewsc3nBIhQGuh zI9^#Tc{i^TYMy`i35fLwomWWrw7wTGId1sMll;GV0>J(UFTe660YgS*MiW*dCIx3Q z`ZrV1e=?P;4lW-qEeb~(78w5Ezvt(c>}tHPp_8WtzhBcNL*zEC+QI*cuwsGZ$;BEJ zLsv{KRro4a5JiY7?kFmkrI|O4Mwm@V7QiKTXB^7w;vrZt;-Q(9j&XmG!Odveo%G7> zNyY Zohl%o *yOr zWf&jM`f= T-1$8+O3`G&ny>d#cF3 z4_YC!%5hc?#Mw2e2X#HZ`FMbZLJRG$S ZHyK}FonCsAXhECsbR z;G@tE+Lw_(JsaqJ3Q3y%W-sjJoy*YoTvobL(Ztf`@R}6;js{uLviu|xURw0n(#)o| zILTBY-6$IejG$nG&HcA?9sx39`!#SB^nAL3ky`MEq8e-@1K*=9v~>c)lf*)$5DKMa zSa%UBakEi|+jz)oEg5L3#^f1UUMf@IAQU1_sA}v;`$U2e8ztEjpGs{`n~FXGBzKBY zQ8_ZPK 5xHCXnZpyEjSB#F{IXHlG<{Lp?Jj|E>s2> z5D86cR1D63$fMMk%*985HAb;@@ES8t@n4xIEnU8&;J-h}WjH6+%RRN4u^Tg`a-FKG zx^MG@hRp4RD?^z2peJk{nwNPaB81?PfOGQ4ms!UO7zAT*CupH2E;sFD7Q4TQCe3JA z5!q;vF4rXkAo#1WLe89oZeX>7zQqx4jOAHu7Km=}gpw94kuU&7-?;;gB14SRxB$o@ zPkC%ONh3yks#2uK4u^X^5EbQEMPWx2_w^y?uGM?n<)QG+IA_D3fO4d<&EuO8jJE)1 zV!xT<-Hh2GYX-$<(7V}&!y=Ac;%s?t-k!pv`b-6;bgjZ*NILFsF paa;UK$*KU=_?A*( zNi;~S&3n+7QSO9)L-TiXj;|S=VO +Th)i=M;L+EpRBUe=x@;^_cAxD_lOX zNHvn |vMx4eD7;)|{m>=zGH;v$b1ktAl7 zsmqsa8h1JGsGp=N$Xu|CzIKQn)B3mkOR<0~s?MDSvM5esWEYpAW^I}KYD~*ga9?iE z^w^By4m{f|xy{fx!RIJkWV^k``)VP#g#8|^2?4QpZ_h_AJGFOoZnabK$gu)(F{=G& z@lI|K9c{mnZ<$n_BX5q)aB%idBRvrIWehOe&*ODYVmeUar14&)DYYxw7;}Y2aep9~ zl;-v1bUe+?Ppavyl2ll60(mLv(sHK?T%}IvUC|I{>ahO 6T05^vTS+NZ{g-a>H`?6p2_K(xSO_aWAzgR8=ruugx1 B^*%+ zQ&90uN7E;us7ZzETC+-$S{#*64S5xJ6NG!J0VeHA1Rg}e*-?BpTA$;!!s8R*ZW;J` zSI oE`W5JiOtF)ybwE;uD? zy`uX& E^6{ zb1oJ(eP}o9;Zz;5rC#2uxefmNxd_XR<5Jwsv_(Peo|EVAUBc zL6D@)ePkfuS`fAD+nLSp0Mbte<`knklvXdOiAhrNd_0!s16gRm3*naS$cJC>wt z(jwulhoHKGPAOEk347=E75o!lULmAqBs3i$m?}b1s9pW mlP?ee&QKdK%%hM7c!If98B1yjBx{Mf^^HdT)qh;!|6t#4$lGf@ElJUEq zEkJTY!Zu`fS>uwSs3?$D*=O910=D-xm9DEt%tchS$PmWI#9)riO)PMSOthLNNBNe|!RQ;- zTc}}I(zK!sf-WmlJ84q++Z5OuHHV;pnK@ gP_hQ21-# zisb!Bd-j*$B=}NQLnYzJ@FtM!zd{op9qXwe!UCp+;Ox_kZ2ZuoyA>EM$AvrEyr9-= zDo1q*k_7|`SUHgU24cGBMga>)X{75$9K1K}JTD8(!6sPme`8?us*Fz?*tCB2-rbI0 zy&5COYj5b){BWS5ogHVYNIzq#x=KuK8ryRC>lcF9=kO-?t;{vM<#BMF7_XD@ Mp-^ph>ytl8V)VCx{)jTucTW?)U=TRP zcUT(fnYN>XJ2?JZc@TNC>9z@6S55yDAe^uFc=Z5u^M6wUwf*se@TTi(q3gKHer%_l z(#0ZMO2fvdYcmTn(WhgQr9-I32K^CKlu@T!@)pq6us*%ZYhbvg{%y_;9*^FeCm-rh zJgdmT*k79ORy`3>+Jn-nL~~$2TbCDq&-T3pM90u4l2;`|9C!2eBS8(xnxnQw_yHKS z&&^$d#ap>yyg?0*c9DmIyidM6kD*Jsx9`PjqYVP1Y};JZ@2}E_^wMb6-#SSJ44NsP zP&E+NEk101>)n`&WSf&kg6pxRV`uAIAX#NbA_lbw7s&R7bGw+S@3AJLOv9JzRjk}& zr!_E=tQrX5$eews<)TQLIdH7kD!Pn|`35df#z9vHmtwj83^3$DQ93tftQZ1UzREDX zy+M`f^!4ptVmL}2|Kt1^(QBr|hc7nzQ$ebZrps8>j&VFt9MDnk?-k39b#VnCM9EKh zJ+c^7X)9;oTgOMS8St%B)kvy$i{F~B{2{6FjCwx)wyPI^(F`-E3MA5^&%r(wF6H|K z)JKr<#zTy8Hk%`HDBPquy(UuN)5kVabb<;xih+3e4Dlu&;3~jr8bEG|D7WI-Pdv#s zRHDBSO^}21FS>sMDE7a){dLtC{DRx;kOxv8dPPR?h}Y);0yP9`<@^ncNe#`b8mdWF zv6g9_HScKmkfPFklYhs}?>Sht>q|NOj+Rv1oVyUOQs6gKZ#w=JFmmgY_Rat7Sx)RG zd=MuH_`NV6Y{F xCt6p@Nr(|UuW2Obs>yw)TfQ+|5!hbm03ByF8N;+}v z*OwxYVkZ2+@GYti&q 5tp?UCB=tza~~HrVri(=$%6XQn=0 zkDv*0{t1wx?_S#^UiG_5s~ckzFcZbwDl 1=DMk# z>EL(hB5LjKSNkqDgw&F69kv}=Iq;Iu z?#w)AZd-`b<~veZRVQpI*bxgrFYqAbfl|-EDT=uU;}D%f;@3O<_4tt_;-EC+!ow#M zO(9ySWjObvlc(dJ-~4w|ve{GQuIur1-uku|$V@V10O`1Ya52S{7!$Qgh5z5MyB`&& z4&&(iAvz)B>A(u!wC9LJ6x+q@nxzCrCU^cR{;a`Co8lrtFnWhB1SSug3-&e_$^ea~ zVvjIDJKk$*fQ5RaOW*??s>6j~`LXk^PK2#)1rjTYnZ@MskCz_HV9VFM62G#EDW;%< zavg;m3-Fp-U&%s`PB~dwfm~s =qGk z2SZ}*CtzR@INp=r2lRP+>B{9v!D+7Kr)-&LHh#z-4&4!~rd74MC;L*Iv>(tLJ?O=s z0J>dmI5`mgLfw NM2D1XGAnR_7%)>fzKl5LuNzs=5Y1l;CWl~u{z5|>w z(9)b5UOXjd>SZZ)hig+VFrw>U(Aq(>^B=U#82(<_ALiFP6BQZry0EYWXu-uyZCOeu z)1Jt}$K9}r=>t#9<}VhMo2)~6SZ*f_o?)Z!7!{@qU2x2%$HHa?y-2OO=5%=nY V2KGfp_w{Dh`?h3a$UjRfOagK44NDx4ucC_U=OOtoFtf9$eX|!-khV_UIXp}j zu?021*0t@?nz824>WvplzR4$K19?P#%u-g0s}JR3-Rl{@qe0EGvpg_gO;T_YW0~(D zRRoz3lmI0X!?3r7uaFA9pzhx_?7!|Ba&)Maz$D*zswxbVD;N?vcM^-DshXzcq{+U2 zpP#BSEvsR(r1$%pGub%HpX|AlUJ5+spW7gelQZizPq5jN%y&@=>(->YT~C5o#|s7( zr4t>qa!=};x{U_A#-Ym)l<)_b=))`GLs)kyAbw#YZsRY)TZVGnv8E?MR%+rhfof(t z2K!owUr0)b^0ff_cXRx|yW@Y56#0uuiH-dKCDDJpO=MMt3O%X^vjfI5nA^#b@a514 zAj#>d>W#rRc}Zi>>ej`_TupuDi_GbfK*hP1PrAc0QW=2oO1Wpq>rZ$?fvs1qTVJeL zTOl1m_*vqJyjSAl+Q|;5lehXsCaG6jcBpL6!Y|hcV`vdF%1)njF@qE^8NyVCwb6mw z^Cq8K7>^!?((C}Q^A5&+(rg_V0Ec3|Tj)??R@|WDE5i P;A{4k#Ao>}eACASgE{0GGhN&Z!A+`#SDG{LpOy?BeyU_Gdz?6o_N?R7#n zXLs{}rXER`^EBN6Qa92b={@c3pYLXIe~~nv1U>;1XF2~kf53mr^~LaC5dR w;ikbEaHw9B+TzI7xN@(kM5AGE6~L0*JgR_~-`G7z?qC&R(WD%H4>j`sh$Sz19f9 z6YpYpYll2MY!VQ5mhQq|ZU*lgNq=mDatZO-rWh!IwJ_caPG 5oUf2aWyvP6rQd?q~d }NgnQ_ JGWQ z^C6p+g^a_{^+&okiPOm+Cm}bxzz>sK(!mXXTYf<(cbt~*O_#Q{z34|}#is33rMM}p z`P44_d8T`@$lvCXBtu9^$;!E-iCZy+S-W{ )iT%_-9i$fW+q6H#H9!%k QqNFqv4@K*-}WB<<1#$M>tlvnWi z*bCQ84>uktHX=}MZiW+1$Snqt^dqRVx7z^=+Y7Zh-Ici_1qmg%)%F4%@m?j;j7KW3 zK`eLrHc{&wi(D-zYrci}10S(Ke|1Ri(7uV}h3Nfg<;m&ITC^bpV366HVpJW*nnJ?S zEwX+BF1&}4{N=~5+xeM*rV%An__Jvuw8D_b!K+P@4`DsEh>$``lA?trA|uwvs_n-I z?eH->*D}9;8AAEugFO&_0xBmXEtlL*S*_O(qn~oQRV`x!?!Dnw7 SaN^0V=GssY#VuU)(8JAO?Qul($6l0P3Rg{;Wn__;ZAfTPYt>r=sLoF z0%p%p(F dHv54FF^hv9W(UAX=Hb(j`3&2GHAPS8tPQ$6!bR|q28RNS%C`g zyTPAiEA0pe6=I7pldI~ed=sG#hPYt9{z+2P>OdjfLA9`6949KW6z-lGT=)CQ((Klp z?TBdX_BAO%?^j>XuUKQuu9dgaU+8`Kal_B0*JEfJeO|h3k1}RG0gL*1#OTo2w>>D> z3UFXZ->c)Lx%2_Q?YSzjPt1oh`xoA@ob-bC13>$%G1PU6DJ#(cI!^kl$>C8L0uSX} zGTwl^;!-?X)E(>*Av1ZK95ON6WRVvJHq2T$Rla8mg!_BMw{Z*3Ud`#evM5m4JsDrI zr@;MDOFvP{Aa&PP3d@p?U@Gv4PrwN|gToyn&|M%;RRidlaHwk489&YrE!i5HsoV_B z)9i6Vzy&(aZcz$v19r}QU9eDhu0CQozIFk=&&OPUet`;PF!Y9_H$K}4-6b%0p(#Z+ zvH*t7Ks*F3QWaA<`;bQT>dF*x%Hk7KsIYy(0cwCLV~G&aEz-SnEvv+fb>Aj?eX1T# z;oMmpi74ImT1jk|Nu@D?TzU3ZpT2Ujlg=4R9?s^}cS57qx?Y-Vdvv5ENXWA3edHT_ z-6bzBtX`I ~x+?#Z_N|(rJW#NoxGqzZ z-v#khj;}x22aV`khd{Yfm0pkaW6GC5lsz`vGGRy{7V+Vei$+zWZ9hH%ZCtM-WUJxF zy-QY@w_f4OLm*)Eox~}Lh|X0;8ZglDr)#?ui8ehStRJ3Ilk9NLuyN fyMia+DiNBRQgj9nPYU7@G;5sN(& z 8McK8$q> zG2E|H>GKO?EXq>%h3 Hm2<;$Xc-dV&mfWH*2F37EUm;+>cFX15)%+KHMj>~va6gGM+9vrOnsS9 z^cB`{8Cv>!uvZCD70t7bBU5t+yxR$`Lz}m5Ottg->h!fL-4mz17m?#8hnwZPj_tt3 zuEicN+kTanP9VP=WC_UZIua9CQ-uPg)su@{5%&Q^Edn7@U_|igq@?CGMA?k6NV-Jt z!7~ruY_y*$6KX+f9rB=wljf8E3B2*C6BHO!{cla*fhHp<2>rh)xGU&~z22}8ev0%n z8WXkTdF<|#l8DY9`%&uiLY{t6DR;5_2NVZYqInM4nb_Cr==8@a23_|o3DO8D7ZkRw zqYel4?#TGSoja!+#D1`bPk@Le*tz)@?%M)7`ihb`yQohZ2C< 0(}mpgQ!{#59C(?j73$>tOd9Bx<% ;3?T%Vt*AntW znMp3`ZD*_q^Tz6dme&&gKvKLAX3cvtSH$n=;Pz+S`83003b<6hiN?^&l3&S4XHy!- zX?ig~pQI5$1NMoYF~yclxT1al2zx$Y%`qrlLa6oP1xU@9m*-nXK^ca{!Q`dj?E8|k zE >e#`; zrG@Gc#eTATU7|6`xV_`o*dLsJp8(PnXty_%2@EHVefnsEYRF~o(oTmldnUofbfE~q zaUvm7j(NHM=_jBrTWnxGq*%Y27=oB+1OuJ#kb4lhpfo+5E#(P*I;dN20;QwZM`l+; zi ^f@IR6dD;SxJK~_4MzLc5oTKPY__$st^|sGbdG+Zdj7PX5NJfpBWad1 zaHtGu2i&6(MCGWX_eIHC#VMznKrw}du$(jbn5*bGNY)YNm3OGCycvR%@LgZ#_P)i- zGE3HK Jvt@Yg;8c`BFYvGoLvh3##o zxLpz)l2v{Fjb{W7bt=3kjO$`%QQq-Y)!T7C#Q3nMv%7pdh2Xs|X#6F}zcB)E;uk_T zT`0YLKS&-C!UZMvx?v``qaL nlEwlo+4ZBuz0UQdwE`ghNIc}k*TBS24fsNdsfD!j-u7VuL=G%cJAwA&^ z4S*sf02CdzHz2NJ4rw?Qw(8vW2Jr{zAFs!)#wyrjxL%6|sGlbnc(%hcpMY@pYc0t) zA*+_sud>S2+u%HNkhXOV++C_KDxdild6_ej6}qRi^Z~fZ#z?RK8c9Mym>Q1bZ{Q_e zEgUi}nq(}JnIFQCHh7hW{33XO18blz)EawDKj*p{M7^cjCIAy=q?S;z9YD^EgvQmE zM L<1ck(W4o#hSe2$cvo?wr(IX1psN(akQa7Z~(*|I @ppl%L>{CRBJs{&saJyQb`X%`6UoCghZ<7txz}KC>jcHX*Lay+J`oQ z&LsJ*syDy+UUryT6c%&TlMvwLAZljxcU?e(Y#AtmX&X$T+h@MLjKNvSn6cvtu4a(7 zO@E*JmgZk2R-8IPv3_i!JdSIUhF6!vin?Nyk;0L>$^Bxo7FQA|Ie_+CbcX$0 wbJ zzYJgsXkfw5nV4_FKU9;}TPHAGR#`al+(=Ti>ZV-ooEKp)L#do`%-S4v;|@nwiZh+g z+ayMv{o__W9`q+|QgD(nom(rQtFriXCH1I{zuOw(a#6IJVTY$cI73{oK|GYsQH+$J zm__RzSZA(phwP9Rr=2p8v~UM%=t^e|m>u?H;-HLbR1<^Da0aD##@3B^19 z{_))V@$U2O?DOos)_&H0*Lu&N#Xl )5m7lMlef#5>$@E}lpQhfY7ckn5RNeD@4 zC}A)fN@{94Mvl95^lS{&)XaR$Y@GMFdAMos^27PL;2d1sTz?k<;^E=pL-8r_@hQ0I zsOh-=-{VgYfD8)A0>Z#RRse_$2qpvm=>yOM03a|B2n76hfWQDC7B3!l5{8}lKXU*8 z5Cq2gvkV{v0|6jXFe&!M)rbuD(QLZgc;X_%Oan9RVN>K(>w0q5a1*bqq7P5M-lw5N zeRQ)`O0=RF&u%I^d$ZBdBd>ama`!vE5bed?LHBIaPq?d@Pj8Ltth!4Uq~V8? ZN%c C%qLS`}1cY|>C~Q|PcpT*!WcRW^u0{D<>x@UJx)vI$Io7maq{IHs^! zT5^M4(Ra0w`oe@~GWesAv=xuEbs)JfZ-GqnnGf81Pn-QDH@mTo_~n7o`nyp(9yQ;K ztK4|m3xgD)_ZSbkDyEk<+?5lR9v0H>E`~GSE*MK6g6#dm>B3peWwxBosL1YgRz_z| zgWK8S{u~qh$Js?ruV%-7ciOd^wN&j5L-6w_hmHxEpO4agERU!luA@%-5$jd QJj^g`SQ-dlrX!sIa<5Y7G661f%&mJ z+C-m*1zuqF$W00Wfq-Bz4hSpKe+Cc)0F&X6l2b6Vu)>ApaVgo@g%uRB0)=8F4a5c6 zAsTI@!sI<`+tgofed)Vel2tW$R4_|YuhaOcOttuR9fXk02F2TiWDfgcyAhp{7nmaI zg20hq%pig;mj(21xl|7<%shEqD=$ sAn&4gS%0>kB} z1C3S&hJOI+t-q-f5Mrp`96Vq9i@J!6>1yPa0ev>{rE> #xz5&jc%uOSXO$ o-UNI^)9W83CPSX9%jC4pnFmL+Z_4x4mtv=Ma3T(`q=EB=(fkeCMdCcBfnAxo= zuN8CmZS`wdP%6PaR7ZCv>)-~OC_KKD44WNLZ?5q9oSE{isvu=%ZdO^vtWbT*XJ$ZJ zh?ndkZJcIxda&co$Ir+Itgo_qcA|zA67_d NqGC|QXhzBy1s*hpm zAp!%UGSH3)Xl-)>Y{1<9+XL_Y0Gne|n?(f?Lii!;*w`^^UyO~@IG^wiwPWv7a5Zg4 zy5>C;FyoL6iI!4vI^qj)xNGB&p=b_qaJZAs9OB>=HXzjWpnF5c!Ewb@e2kw!5pkmk z6(8gD3eR`Wt7krR3XaOd3Y~)tD|7%31Y2eQGk_p6Fey0#D|EP!0;{|p>K~C~OSc?w z*fl_4pfmh)(SFk7JY|tfv0xczy1-}D4+>)yjnxJ2{}|`9_o1|+6m`CE7H7e;+p&$* z+qz{CcXEhuLS~5x4aaC|Wq$5><0UqvpC~BKXGU>3E4jkp_C~x9)yNT3TD&bdwr-M> z87<7d`z+x*($BSah$vn%`S_tnBGFG89;U}w$ShdMKoH*lb`mUPa?-zm^$=kBf8c`t z!ma *cKPH||d?<4Z?Yj}^t3_nG^fhIE5cf1fm#T#P(gP}A?{V7>0 zu59>^!*S)k4w?czMMWiLJZKEGhP;3>mbB17a8_`Z?}eb+uMPY7n(ZI;%7kyyH!r!^ zg`6$p&;J$;aZ&&f3<5*I5FEUJ9VXVg$jDj1LVBbWtO^Jev#>l48(hTem7;!f4JGnr zNMh3Tzbgnt4s_Z~mOHdt`?YdJ&$d7%w_sh8w;<2Nx2LL32e5Ya2k^Wc#md00TH0FM z6>)VKncmRhR?)b^-8YOUgdX1?_6VTY6vwNaHbb$RCGCZ#FP|f8aOhWN JQ?;bo#GX(yC+8)fA4!OAOcfJ+B7Q zoL;`Vai*Lt({6eZwH4+c(
D JaL^ ~o4Is@ar96!Dg5 JLU z)cAdV*W8@JVj(`S@R8IC^|yL2W~g5#d}{qMa2m?NP{3YIATi)z8Y>s?8Ir(9Fsb*U zVaI&o`c8nu3-%37KgG80#XkUwMVL{`;G7W`{pbC-C}p@{YqT{L@2^ihCOO)|YsoS` zhiRykYNmqEaq}l$cUq4fFrK81J(tt^?PWbh0du;mHpO`3`1}g1CHjRSOTN!P5N%#9 zKMp-G-2T{n{uU2>5*xM8Y#Xbw`YCuf5SqxLp2}lbqF>~!U-U$m9zffB0BN; gSo;aAb~V=-?y}!_avuO!f0O7rL%UsXZ6}S5kC`_chz<^GqaG5{ zkTAkNijW(l-`##04B>zN7WdKV_LM(e jTJ2%SmYKR-(x1VHBK1#nvuwNBtrl2(2rTZaVI0%f&7+j?lHH^tYEQOVJtes z6=j#Pvdx?$lCnIeab(t3vJRbnYv~CoMgBxvti?ySb`Wd}eb{uk>y?!5C6}2R7D-!N z)gZvTY1Nn4*ZU*n As`Pk+52m<1gj|dbb-Cbk=HftiZvKYkXc?pTu5PCWt$u zK8AXbp<9%uBOYVhv!QSz8S-YU2|B{*p7G&B?BO}ok|U&TCn~PY8;voFBJI+>Dqp)a z{-i%7NsD)xhhGPu7ME1Hd9!Q%BhkYtN1X^)EuES~r$nny`cT7~`Er7q@|$>B94#L` zr7YT5E(D4mJdbhnXS(npPv00bl_tdPu5`RVxhn1rN&oyVce~%6Hj3S4Css~Zn@Gx1 z+rCCxc<*qA^E)5f6&*EoV^6euu(PO@VF!1yi-g4y!bL>Xnf>cc%uU8xUa&O3ua!eN znjHk#HtCwhaMkXj2V!_7VpqFR%K5649VAKwG*-@2nsicyV^7(}5W9gdn1GwCqp@nS zZ;9*~ozU-&J>HNF5O&efMn}Qz` *X{db_&Nk0hy2#ao${%!@ok3N z_Xaq5DhjE*p2k=<*L-VM(#Rv<9gR;c-e(a{kLLKbCqA=NbeRw;*#D+oNy%_Jnoz6e z+cO;rY+3rJu><@~*QD@iy36aN4ZFOQWK k2au7n2r(m9+4{dJib=x>XW{X zv#w;sO(cxudeSPGUs8r6$zQhB{deca@L_~7AD`CEr6bF4E4V7ZRxexdBYz=URPw#H zb04okv$ u+4SFHq!bUHEEMYH7zUZ3$`SqiHb_7)&ta z`8e9+E|w(6KP0j34H);|p%3dFq|7W>^FYB9w-EU?)Boc6H${;?Pmc9ELxBAkzerBB zCtN0M3ZiOkF&Fp0X#3{3bDT-~2P9-Z=X?5OSu#K1sQM6Gk~GOUd<$O|2AekJ(2vx) zc|57cUSL1N>c}OV4O0-+#8IV0yF8O_5@e&Q|IkB`a;Th~ag?NL{VMqT{kA~ACd9^z z?a8)_+p4=g->}X8o!dx^r&2ek#mrj75i=8ia%lky_9=eSy_EBzo zlEi)i>!I;jg7^NKBes9T`HwdO{+c6}9s))BDlxz2lo`DR|4;P7QXKATX0`q_zXey{ z2#COE-OZ{@=y3&Dx(y0RQa&Yv@37O0zFByUE=`@Hd3&Tp%Smf `8@o(i6`fh`o0jPXnbA->0%Niis<6O((gJH(N;L7I+;YspABuYLXi z*b14(TlP--9UNa;u_!K|fX*r%DDhKh%!p*uuc`D{985B_pogO%;mW^m_m3^;a%fLG za|W#Iv^+BCB8gzs*3x?2IOna)ycTK4Sz4l1;W80;LXtY6yXgyy{cM&p7;+}yz^ 2{8WEXx2rl^E$Bm+S1bUuu z3h@-rMgvd9(NDdcW8w Jhki2N z^ZsP|ViRax#GxLxNFoojR`$rLaUmBM^Nx)DC`PtF_AHIRCg|(3-B4Xwvr?|WP!6D6 zAVH%__{UU3HuYc}oA&Q?`WV((10N$HS10cLYO>2T1=yx^FbAXh>rcJ&t^=v^j#P=i zi&y7X#hg%zNfz{L`+orT<@z)F8vGM0=jJ<6nU;iLZLR3ssqWDCa)?9qCF9q6o^NUP zJ?@;IpYZ>(&X8m=j_K8JA!HpSfLX6OB$c5B&n@`qhdv65^+90$xHA!oKhH>um*oNC z+%u4`D4275g^_9Xqi*{(RlXNqJJsIVyi)@Q1 =sIEK>2UB#|>V)O9sDaj!54MFmGNEHJ@5ONwXZEF43V` z<|jxfa!=qo`U7CVqu+eVU}Ei%!=_ne;2yXwo7V1?3D#=;KpOROgTfzKR;2WvJRcYc z_+g?(D-SgZQap;WS?2y2vRr}ig?-Or)-B773n=2jCe)p>%A|zt1z(92f(L`;l&Se| z1G@tUql6ckUTNTW&D^7oq_+?>>a=Hdgms8Q-mXKK^4}u+`QNuV@drVHy;)sh 6Ma%ah)K*4m&1Kr`jY;ss4r^WPoAwR)L3Mf zxJ&C%%dfhcM51Z%8R)sOzcCWYwoHqCWP0A*_~Ac8LcXJuwYL@flfr)#ODwWjS-Cs$ zv`cLBmMtp~hRdh8?D<;HoOU-nwQv{0 ?P}A;KIEplI_bneZH-SfIK^8dXPb4J5 zNYum}$=k&ZVWs&D3NF4XFZUuQMB3$bAC_icr~Fn7cdnRMmx;tT4;eRj>F7yG&l9z; z^hS)XiVl`d !;&XH ic{!9x`-gqy#ZJyl&SJp;iXEBaIN#js1L6}3%AtTI8J zxX*640Y$CFqWq{?^*NevM2XwLL}drz%2$Bti2lhD18 *@&gaa|#O8c; zFZD&b1G(>xz-{WXGZN+486(%5w5$?~9*xmxHK&OCs}TGCKICFcEGk@ot5J6ZxlVfm z*xxpN>rrk|OVrH;lNfvE)^D88P{{p4*PvGaG7Ka88~4`(RwBryEf*(+>+8Do=2stR zFg#KZ99FJl*DW_Z+nQ~&M-upj7u%q<%1KM6>SJ(VuP_5nD;mRmcQv><<~crtMwER5 zQU+aLyGcJMt-5X4lT4B2RXvC2Bx@R2Y|^C^q&yHGfan` va#yVV5z~TtG fLiQsG7b!xlWSjK&5?%iPz@SfnG-riODA|Y2h -|Pcr??$7nYFxn7@7A}}8d~CAtGC4knml36TGlLc1ltB1ebvVk z<@Uq5Y^9zW)+qk0tDLjUs1AOPcxTVwLI#ud{y7Vp!t1xNP$X&42jbu2_UWl($oA1t zCehJ8g0>WoZ**BPp|t6i ot=%H zgM*zD3Wq|uxS%NBLom1?N=Qf$B_M!4EF+E -$jB?m z{}KUmaBx65p?pv%pFCOsE&u 69WDj|E2%{AP5XOm )$k3gp3QEfqdasF7!5qqPoO4EF0jV1F7ZTaO9aD0w{ z+5~$BP3;ZYoUydVg?rk2M`DeO4C8%c7`v!-MZjD5^_zl%ksRgFn}V0UsHGB 33kd$J~-~X#0nL?^|k1HrvZOnPqlAP6$S)v?PkSYL0wb z>b#=fs`|E&2K{>E?g^k)i eUcHQ;##j&(&4f^y Q#oV}uP1>5u6P_Ds+J)4%I8O0rJ|`_h91j9@^AnM z1YiTR0RiB@jRXWCz;GlVMnXjuf|At7s~shnvpmJgav_in^w~EflMn0M!M#e~m6W=C z@>MvAv-A`RuBul*dpFFOFp@5PDxl7KoN(R=o19{t8?bZMm@sszEV1O$M`f+L?1H)R zi|El%)9re3o4zlWRFS*dVNYgF= A2K%QOgnI@f1S3^U-w4@1L6!bQQi&>uyQ$ zx&V >aft4Sw2GMS1T6&iHG@i1^NMOIGW%g8inT~FXD-4}QC&?FPh$&vE3s5x6j#2DM z%@h-m*HxmHr*Sp6NNe7w$bczQD9!W~A+z^YH+AvkJ244|6{$|)a 4_Ib5#u$H283TBB2?p+($Fy0MaGFVV%#{0M%go7X!BnUS%Htrtd# z4g@8(oPi6E#KfZ%6r7M_dI{%WP9$iiU6Bs!-w=Dqss;mRb;jzAbr}C`j@21P6;G95 zMEItw{MY7?J`RqZbK}?z*9SS?Sg99Hxi4kI%jKM46bBxG4BU%TiG#ND--KQb=UW zu;Ha=FCWe`gGlg3BAzQ$fl{m!bPS$pa8~Z-%l$(6nBcwL`q>#JI}FN%Uf!ET36Biv zPmdEd5DH83!=$Nl2;E<#osKstS0GyyU6!@zVe*tRxKfe?M+H$PTV0{lGxj5_RQv|c znW;Kgy=^f+zCl%Eeo)IjGIyJqE@D9WqX>r+$kpzT6nJJYAKgtCgP4lt QjA |KYZ1kMkQ@BRR;ELPej=qc$2+N%(Dxu7Zh~F$yMmgPX zA9IYnkVw*XdW9{%Of$-ew;Q~AQOunZ6Fqc4RYR3ny8B=dccDle@^#B@ginDIJ!p}{ zme#Y^bllgg^U34$39SF~iSQ^o^mRMVn^h*-QJZ3v;8~ROTBFg&a12KDAXOFB7JMV+ zk87yP%YG!-7~15}q#gsYX0?(zx#B>7&;AZ&QsOjER3KATnQJEP;x#hmDYv9oo_w1) zq~0$`m5yF7-_zJG=Kb(Zcx{!q-!~D?LGCIQlWCn?O2ovhNTy_#2u6k`K})>?xhGCu zf04kOWXt6pKRY?LpTLJoXWn*ld3CrMMOn!zbs(c{&`w*F^n|d)Oz~v5CMx)dZVz&n zxn^3SlFDV~Mp17%24ADH&l;6^IqYJS!dH6nkvroS=SEi*pkGULlYSQQ%}Q@i$;!Q@ z_*}VBTXe+J&E;!tDo@398kpaCxy~K!x_>lL`y<@a-A3qiML1r~&09~{I^YnlutH}J zos~u$y*IF}e3Y*c9dzW)lj2qQZR*csTgs5COKfkW%uv+hdf@UhVuLO7hjvN`-vIzp z@xp7VWySP#``4aan7nc7-P?4iw|q=pvB(%QnbUbFKCM%(_&Akzr7@*iWU{t8wa)`4 z|2CnK>BvLBYFZYE_O@2Bsx7 zXRZX~+%s6~f%nFTy;BPgxcTKiqiP>|eowacEBR MZLCXCFKApLjG&-iLcCB`9vv+=FN?N0i$Defo((qsRKIj+L|ArqB zz~V5T%7FVuq!%}iZfyQTKe&0+oGMC?I|=mMgUb-ae``-*@8av-tOWya=<0DB8L1P4 zA10O I~_$_KIa}cnAclztc%O5DlgVYK%hgU4UjyZP!!sakUhlbMc)J= zF8d>+IAeO(2%mg;ZPPr$Yt)1})xPAZpe!N`s-rdYaGqdB@CbpU4{|reeAk-nr}ShA zOa3Akdk qE`6QMOE zB`;@(d1s8#c|{4F_aQ@mUpC7~<>~V=5!-$JN}9dxk?{)HCyt$Yzb^&3%BYa_u*wsa zNo|*its9sVxi(L&BR0zZ}vb$o=N z_0OoeBK|&sl-- <_Obgi zrsV^AY z)3u3BEjH$|T~g)uXdP;$M9<}f _Gi?RUCXfYn56aJ?CP{=^=GAF$dLuzdc zGf*uyb-bCaALk2lLf5n^_cHQY37oRy*p~djltKb_In}JqM}XNA!~8iErP#>)JU$QA z0X)0a0i3cZ$Dgsm+YOB*I*{=?JE%nKA>7T6Y#y%~VlMO;mn}4Xzg`~BEXLW&{HD18 z*G8Rnq@EKZ;RFgUlSPZ0x%}pdVq3n+03YHeoOEm`i&p*pVdl21yktdQB9zfiBlKK< znE!~J4Gn5trau_k$fnvizs13 WciwKEP;n3 zyL25$e8B%)e^$?8?V(!Q0++X`6rP_bRhA1iEMHz 8q>JaR#)NL2otl^N4aSN!9K*yf0-%`F_TGy1C+$>H?zMH)y zdG?+J-l@9HiNVV#w!E5y+dS+ecIWNz817*Mqwbt~_RgX2*T3-i_q7^ka$Pb3<93}Z zP-lXx5HIyikj;C9?s&%;n|I66OFZ`Ds#xIFg%e?9(c8|Cu0~8wc8lFgZ4N)=?22<) zJ8RN?Kj%u_SCt9IJnYiRI~V(Je-o9e(&BJQ%=k_|pO~n^{&Bds)>IlH@TmEPuU6S2 zJ)62z?#lK@0ZlGBrrf`3@bNoj@u|k#UD-29@ldD^8S^m!tvR*i7$Ekl?0aHYCD}vc z)6ZVEFw2wN>RwUKRtlw^1&{CTW|iMhN`19ojN<;v9eUi__Z8%92i4=*j!y}~wmr?0 zPdIRUu*URm&=BQX`MkXU+uDRr;XX*B&lLI# )E5;Es;9E@`I&`l$IQ z$x|6LeT{)ePM4{VtxIN&+Cm$D4ESg04>sq$IFFfWqzWjCKYRsEF*B(+02s@*&lzz{ zX}*<${-!Z7(7xMMxO6*6Z;UgFBqnUtYoXwfYt8qZwj7x)`p{p3hbJm|PMp2t)|dlL zY5M&SY<$l!-6uNG(ufvPp;mK7oWo+5I+$8ahD^fBl<+t2UBL{4bxIN-(9}AZ$w%c@ zR9R`M<(3J2=AK5&0br_SqwC@Rs-|ogzDjw H R;~zVS>>Fg?byWL3 zY)n1+?8;ARWHaHR5mq+o75!&818e|0=3i*~VDy?qC3s1kS6OYYqm4#tXjt=Jod*yP z4WIp jvuGhcsFCwjYda(ezAmye&$po;j1jXtaKCJ3s*9@(_uE~7AR )W!g@dREfIn>cf2(6@2xLx|@Z1uR53VQkMC}T~#vEA{dWb-qzqIFh= zYEK=ydY?CFkaZ+yjLdv$EyaD@Ib(Sb@fn1xJ$5LupLD}i&Zj}Vtrrk?S|9rEqpz!! zmg4X4WuZyI*%j5mmwg8S#sxHRoGw|Rc}$AbyXwLr4w #_w8;0paj4HV&h-~ad5D4aB*?)KwuE) z!2=K(A<;uHB^ebJB^d<;4Lv&}4J|7j1qBm?iIszsn}?g4kx!71OOTz5o9pi&7`V8& zAUqH$2t>+7LqWs!f3~}B05Klm4F(k!1`7a_7z2wK nh509gND-~Gp!Sirk^z(Xty045j F0l}V4PvM=gW{DwI;rUC*n*Mo zFtxI1yS~1dQFIcu1y{QQj4Z=8KTR=| (o2i+Cv{^ zf*jRUS;p1+lgIUor}Kh*T|f0+(p=Dsx;7a`X(z~FO?bumx~7ZJD5J?+$jU3Hqa(hJ z;(Xj~Qi?CvPEYkRu#~6*SG@##eVFrmftWkET%Pt?xc)VL{J<;D21#%boiL|ID>F8h zB_Zz_pQL0Km_;~iia}k?ri4p)!OQowf=tv g zPLq00{E1gQblHf0_P~Hf;*I2^bsI2uCN*i} %PfFrc63U}iOn@yYd4RRqUtg9K9(V100s~f0}}@Wcptm}*nKP$14&51 z%-Cd1EJ6x`Y{DX W~vh<$;Eof#EU5LLGSYT(sAGu2ARQ{54kX0jcE%?K~A#=XxTv4Gy=HhZc zwF?VPx{HgGlatFo23stFbxdyr4zBvgyST7IR`r#h$T?Nu)!1m)X#ZmxTqXMYFdFY% zn%vynbePKDNB;0VM5w3)S{=PCkvvHd1XC@gfuo^H2@@+4eTfJl+;~DgD#1;gm_^@# z!r8Uo>3&8Rf2os_r=n1(0u`IBP#Hq%#XBe$I(XETmY0IN!9_x5e=>&ueP8nVuOp|l zzT}x-{K^K91IZM7D97NCC!PKuN&K(+iW-PdwV%m`W{DozM-{LOckd0`J#L2IJ7!eY zs`bZHU~_?|fL37h$MFoOt0;Uxy}=|%oc>BOSMsILUglhrE>y}QDnm=_!nDJkJ;Fbb z!O`n{eE+<7_q@zXGV;d9sW^@cVa!r|=~I%15+T@%zBVyc_~0!w)K`-7XHNMhRcZnM zqoIu7+l%@)c5M*PAU2JXni7%>x;h`_GlBS*bE&hRs^BMsUHxgJEXC>Xwtp#Ss#fa^ z&YP#Z+K%ky1f}Q>iY=zfDKtv 52F-NyI1yXVlE4SeAGHKz@-s!`4>>92|IAkMPTd4{S9M zh_w0N&XbQ`rPbEkbe_z4&IyUl6mT-rAYgQEoVp|_rjXjz_KZ3o4t~XYi}aZW$h^NM z@zcf^;&%WV^>@C!TK;a~!Ed!ML~`>aI_LAH # z>ywHfr;NL{8w&LIFf_*`uldOK$4|D4+yUyAH>+grT`{j(p=dD!h14p ON%29dxa!TqNwdyu72gEw?C?R#3V%gHFC~2pzKcKK9?yK+ z#9NlQ&ZtLFEpvbMnv$L3EA!r6I6LI+D>`Is`psg+($>(lYF21Q>=MBiKK0@`v5LQ= zfS-lHp6*&bSwqOd2u*RtVR#(Z)N1LiwBez83o6)sH?HY1ud( 2F4SZHv#uVRr!D$?jv_jB7lB62=dCUyVc)8ClOWDq4H{tO#D_B~r!A2e)lJH4GNv z{QTlON}(r;w5m1qzO1kk128c$?<)(|e;5=4lNe0Gghk3MBq*!^v-zi*+|#HWM#BiC zVPwsACcaM1JIkTENEJo7tHE_}PG?EB>2Y8i%nR*tFk23o&TVM?o1+=mT C zWcplaw0gsViVaJ>U5aghD|s9*o@wmCo5R?bT$*H(Y#!Vkh%9_&=D^Y0!K}|LLnmCG zw6s2v4a*^FQ&J9**|+?;9X{um?ra{C^%~dvsWi26_t;tf!H$XfKREusu`^={kqZ7B zI_6*KR~7{*m`b%Itnrqh$&cgxs;xmB%| y3EOXt2q+Dv+%+((YZlDjH@{q|eo zWADp8r8}ey7Gjy*rl7!i9z|_C{ImscPhN(wG)k!dYH(nmYvin7WYmdmQF~4|g1;Vf zjJ>-UK{Hll-ExF*FR09IDXR9SZUJu4$UYMvdQ7M1%mR98ygS_>OpxBCm@MgQ*!q!T zE77}Xbwma9!iGkxx_@X+Aw0sTt+;1MZxa8Z18|K%TLQbZKJXVQ4ijY1L8G{Vn!@OY z!9&Ao{m=xvRQ_kvv>cRqMLJ^*^UtI`hepF92mu z(}9jzP|YB|+2>}720eY2TRYzi;s(?`q0~vm($k=YR7h!{Yj0I?*^9-1c+Ma%ow- SQ>EF0l`k?{?ZNQbJpQ z*>0QLKi!U)8wTMajKa3-*{I}gl2DRU4DtP+T?2OlmvSpxV_dPf<_+*Xo;_4eO*l4_ z&~9IbO}qk!n1rTS84q8qkgqTXS4xo{WVFYgPdmK0ZhI9ex%G%Hj>g7tFnbS$3T#D< z4R2S?s?3rR;X5IK8j191sQpjyq1t*vi-l@{tgB@6b`8jIcm)ai?o*#Hx@QZPjGGVC z&puK5ZDCNwo6zKrM2qHAEPuNL+@}sV_+GaEwZ8@H9~FcFxX+yXRQCplr7#uMPj>AK zE+5GMTLH;2S3D`z$l!TeVMTs_``5ePOX2J4ApU%Gv+}h=9mxg>q*_}a#y47bTX?@8 zpvTm@u`C1&o=Ge09OFw?Xht0UsLlQJQygAm`zqKR!fl-fjgKD1UX^9e5l0_i0K=)f ze3H4b-mkk`>u3aCWRIUA=fY49uGJh1b$UroJ-3Ye+T2pQ6`tXE{Y1}fG-c36u!}6= zGG@a=7H)h0ia}hDqQluwuUY?)TI0FgX1y!#{^7W=;?J+Y!g3ZW6zJ?x9AULjj8Pir zcg@dIy%(frK)G`uJ?GDxz)}eJx$xN>k53$A6ndb3Lgy>{=Q!%od62G2Na@;bD39E` zg0$J6Cl~Fq3?yxGm8{zVRJF`MWcrjZ(xFe@GA5<(7rg&1rB$M36(FN{Gf?7ltujxL zAMRt4>0!ANvA8B%Gy JQ~y_%C&YBax%7a-no2gp8{Hwi7Fijz`4zv-ErZHv?e>kVOo4Uy_J^Mk-ZrTw2P&QX(or0?J{XjWPi$_*tf); zE8OcUm+L}=v=`%YpFt2uPGqk9jRN$~3blF};u`&-49D4pdGM&%rQs&WfdzFHt&?#K z=k2&n|u(?z($ZT53u+nq;1nDLCov%-kl}2 wgZDn9d&75Mgfz#Emz0%glNS0e!) zQv%^WCf{4Vt#rm%MH)zl&17kfnJ^c|M+14ir|cwm0R3P>mkc36cO#NT@rMH(x)5mC z&)05!yr(412gIMW8SFu~-Tbgb`v*hq!;nh+=hoC%iXRD#g}Re%H#a29bw_Qij3YL$ zRhrY#{9j&iK-6-T{T1Kfky`2AAQ~evo*fXeHpExU=(jvya^GXWirO6eJUoLna1kXv z(UHJql95e)`+3x`V^)tS)Nw6(oicU;?MLcqMZ0gZ*mkc2&G_yBY%Z*L-PSL}1co_M zc?o5=BAm+ij6?ZQ##AGhE6a;V+@;#F*%86#abC@T-iAv=Njxp1q(WrvHhdF|e}jyF zZ5OLrvzXvl(W}pUm9G4Xw%}!ileMR>=BL68c%+@JXrKFOPV^4JZe)@Q!`dQmuD)O| z( vAIT?{itA)T_j0t|Kb@Q*VY{!kMCXQ;ij_9_*m+njaN@fqD(==~9xCfHppn`? ^L(q9p8H+Jh z!L6$+vZODw1$6Z@5?so}lAsXXIn|C}^F91br1?xz_?rY_mIKBKB`ez7Fl4%$11&rK z(HVxyIjhptZ-FkK9wqYRNRmP*+?DqC;vInJ8OiNWP?`;(4GMYBPO7x}QKwwwiMQN6 zq5N}X1o$hH!Tmm8KmBPT|At4d_T-_kk8w Sdg7(W&5qF*Ua~^2O>muJ``-kml~cohYeOGYEA4d;G;njB&ryzZdWS zJ`(`^Lx^An7?Yq)(SM{n`1*@`(}ElKnLlgWmyREt(f#5+s#0wYb}<(s$qjZ<`zFsv zNCngSO%JMzN3vH!8uB~nP6!|A+>i($Jz{xd5)cYfjVvm!;bVn5_!Idplt*`fXTLqC zqw4%DOKiIi2S$7XB|hv)ID0e$N967EdWBc}%Jmd491jQlq_Gyqm0xBiAr8KnBV`q~ zA;H;N3GJphlw;>dtNeYL*n{y=4 T!m*>G+u^}ShHC~cC%aB*KL!d5Sf *X99eb>L?BpK zGj?om|1PHo4AtZp_0decC-T{;aNJkAd4 Ke0X|0XjAUy8GYxBNW{>fxE2Q%%V(P>b-D!2mg38zn($zf=HGaH$ z>Eu!L1@jA=&vX-hLCT7h#Td-!lJ64xiA-tu0M|;8uCWxvUyD)Xs}t#F?2`f*1QQ;} z;{6q_Gt7+t0U5KJpoA|!ml?WErG$DGTA@+XR*<|On{Y@Tl8y6BsOgN#Qje_t9PT@y zF#z^}i^qoS2e2m|k{;W LD2GTl^l@-q@pDLWlaK1Y!Xq*WeH#yly&l|KG z-mW29ovhFnpQpXkrm&KFzn@m~Sig@sR}^@xJ<9Gq%!AvVZJ1W=BIUMb_H@6#0tX)u z+&>wINWShP A20wbqs1)9*YKVx27o6q2`7;SY>esw%e_h27aJ_XpKqrK zfmtm!+c4B+oKz c0D5T1ixRXRWVx0|z81gqMgGjk#vRcVF%if?$Ji}yXbGP) z?HF9|Cfs?MF|vgFu)OGqj0fxKDCzTjx?#N~A*E-Ai$8F9rF}5v;tb3_TF5 f2f5i{%5r^GC+Z?~iicJ8r`S@r4ql_w?A+uuar{WyeCto;q)L;%!gb zp1q(&(eP7yXj{A7KJAv+ccOT|-j{ATrCF-UKpPkSy17W=KtEV=8Z;bRUmcj2!)=tt z2<9#v5UrNQT_@(sisG%`fCE6Jr9Ed-@ga6Ty1uRacYyC2@koiGqF?(ACc*5aYDGD3 z`K#Bg(kU*;#C&9}<7{y;un9GyNU&7?G*>6XtfPFpR)}5zY16$Fs59;WyNZ+ASx75y z+I7A?`s9|;2E5_b$2STVPYWk#q?@XHVII56RTp;fPfc7j4{|iCMQu9aA=;(FRy=!e zTO=Di$p6S1LpcN|3+7$+)-tdW3v z-@9!5=vWKmr!n4MP1gJTLFKh@dpQAPwrLPw=Q=32mrq+SgZy0^h@XyjagsY+yrYAO zhe?7$elvnq)OCeDI}YfdE7`kX#JAjj(W|cRRn>f3W)7wV`JBX$_V7^v{c4mezhhby zxhw%IQo?u=tcvR3Di?~q4D*cHG=1Qb4imB!9_kueEsCUib_QDhT8TX}DTCY#kpb9A z%M$_)tX8yy{x$62*C(}HO=|nogMRBu4KqR~LU!D`Z?DR{lUergEaQ4mt9=7C4Bgms zo~ S7J+B==iJ=_0}6Pk-)wOD!dG@(fuI}9yZZNf3aO+ zx~fXDtiv{CC$)Lp0Dm@5?O`7iZ@1#9uVdia$@6+N74h51( n`Rpd>-*Vvt95RT$=ewT< bne5ze znZB_1dn5C)*l4?|U6H>hI1LO=@VZ~`dmVK_f(E3zrdyM^Fj31v;kjj}4?hRjJEJnv z9|Y7M;FTSWHBt}kYAar{#AJ6HgbK+6roBm`j5KewOiZ5=FfE&||3N#c7{u$IvQCH3 zYF=zS`NKN5Th$rckQhRyXsBy|7K8K6(Ul#nhOkR}yNO#}(adizjbE0cFr%tJb8@!C z)d=S0f2pOxpSY&F?h<;(Z1% zkEMt~Rh@65fBhvfwSinz>mY z`%B{^O0n!dhfHcbWC@v4C(g4+1YY1o)-2YA4SEyIN3c(5#~{x!jfJhC2STYQ1~ax2 z&-8zz8|orDPaSafj&{@zN3*$vyMI+i>QckM3x#CUoCDb`4@V#$<#{@YLxCtTj~J7S zFR6%4YS>MJaH>PH=Q3~l^Vp*c`C^8xk7s1bwe; gKcXj>|Q( E{u%cc9I$BM z$-wEmP86FwMeI!~ @xy%-~fjAYl~VYesPvB4sc+2;6ovPTE$Fyvy}5pGRzC{68fH~?H @L@WFPVD75z%Mc2mYld9$3 zpW^erV$A~C0>(FFwog`8_V^z9G}23kxpx+?WfGi6P3pYIZ@4X#$AE=f-*%J&$PI~J zj~vU__dQj#An3%t1CXTX(kwA9hBzgXAXenagJF9j-!d+64u5AvNOy`~cYPxuSBteM zg&c2OCGJy;8{Yv!nC$WNXjt?8%Owy411g%CjppZxR|zQ5ZPV19-p>HSAZwGS-$_0p z49qr=gcwE_Z_`aLA}D?XT7CwrK)uDWSq#t)d=7 qQEi@+vHf3G36>QNLHy2Z8~9H#SFxh%4W zoK*4|6|_}G6B4Xaz1XhM;Y%P9PLO~^pp}@=t#0sn83&r*K^UL(!WGJ}Lw6|vSX6=r zm*GlPMT0j<6;Hk3X0}2HFfURK>$aZidJKHOm?%Hn>n<) !gFz{h;m0nKNDzI-c@>}J>_So@rsEC<#O1paw}eGU23C% zt6| xa)r!>29exo6yON^&1Xa -1; - var L = this.options.sliderL + this.options.sliderR * 2 + 3; // 滑块实际边长 - var drawImg = function (ctx, operation) { - var l = that.options.sliderL; - var r = that.options.sliderR; - var PI = that.options.PI; - var x = that.x; - var y = that.y; - ctx.beginPath() - ctx.moveTo(x, y) - ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI) - ctx.lineTo(x + l, y) - ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI) - ctx.lineTo(x + l, y + l) - ctx.lineTo(x, y + l) - ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true) - ctx.lineTo(x, y) - ctx.lineWidth = 2 - ctx.fillStyle = 'rgba(255, 255, 255, 0.7)' - ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)' - ctx.stroke() - ctx[operation]() - ctx.globalCompositeOperation = isIE ? 'xor' : 'overlay' - } - - var getRandomNumberByRange = function (start, end) { - return Math.round(Math.random() * (end - start) + start); - }; - var localImg = function () { - return '../images/Pic' + Math.round(Math.random() * 4) + '.jpg'; - }; - var img = new Image(); - img.crossOrigin = "Anonymous"; - var loadCount = 0; - img.onload = function () { - // 随机创建滑块的位置 - that.x = getRandomNumberByRange(L + 10, that.options.width - (L + 10)); - that.y = getRandomNumberByRange(10 + that.options.sliderR * 2, that.options.height - (L + 10)); - drawImg(that.canvasCtx, 'fill'); - drawImg(that.blockCtx, 'clip'); - - that.canvasCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height); - that.blockCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height); - var y = that.y - that.options.sliderR * 2 - 1; - var ImageData = that.blockCtx.getImageData(that.x - 3, y, L, L); - that.block.width = L; - that.blockCtx.putImageData(ImageData, 0, y); - that.text.text(that.text.attr('data-text')); - }; - img.onerror = function () { - loadCount++; - if (window.location.protocol === 'file:') { - loadCount = that.options.maxLoadCount; - console.error("can't load pic resource file from File protocal. Please try http or https"); - } - if (loadCount >= that.options.maxLoadCount) { - that.text.text('加载失败').addClass('text-danger'); - return; - } - img.src = localImg(); - } - img.setSrc = function () { - var src = ''; - loadCount = 0; - that.text.removeClass('text-danger'); - if ($.isFunction(that.options.setSrc)) src = that.options.setSrc(); - if (!src || src === '') src = 'https://picsum.photos/' + that.options.width + '/' + that.options.height + '/?image=' + Math.round(Math.random() * 20); - if (isIE) { // IE浏览器无法通过img.crossOrigin跨域,使用ajax获取图片blob然后转为dataURL显示 - var xhr = new XMLHttpRequest() - xhr.onloadend = function (e) { - var file = new FileReader(); // FileReader仅支持IE10+ - file.readAsDataURL(e.target.response); - file.onloadend = function (e) { - img.src = e.target.result; - } - } - xhr.open('GET', src); - xhr.responseType = 'blob'; - xhr.send(); - } else img.src = src; - }; - img.setSrc(); - this.text.attr('data-text', this.options.barText); - this.text.text(this.options.loadingText); - this.img = img - }; - - _proto.clean = function () { - this.canvasCtx.clearRect(0, 0, this.options.width, this.options.height); - this.blockCtx.clearRect(0, 0, this.options.width, this.options.height); - this.block.width = this.options.width; - }; - - _proto.bindEvents = function () { - var that = this; - this.$element.on('selectstart', function () { - return false; - }); - - $(this.refreshIcon).on('click', function () { - that.text.text(that.options.barText); - that.reset(); - if ($.isFunction(that.options.onRefresh)) that.options.onRefresh.call(that.$element); - }); - - var originX, originY, trail = [], - isMouseDown = false - - var handleDragStart = function (e) { - if (that.text.hasClass('text-danger')) return; - originX = e.clientX || e.touches[0].clientX; - originY = e.clientY || e.touches[0].clientY; - isMouseDown = true; - }; - - var handleDragMove = function (e) { - if (!isMouseDown) return false; - var eventX = e.clientX || e.touches[0].clientX; - var eventY = e.clientY || e.touches[0].clientY; - var moveX = eventX - originX; - var moveY = eventY - originY; - if (moveX < 0 || moveX + 40 > that.options.width) return false; - that.slider.style.left = (moveX - 1) + 'px'; - var blockLeft = (that.options.width - 40 - 20) / (that.options.width - 40) * moveX; - that.block.style.left = blockLeft + 'px'; - - that.sliderContainer.addClass('sliderContainer_active'); - that.sliderMask.style.width = (moveX + 4) + 'px'; - trail.push(moveY); - }; - - var handleDragEnd = function (e) { - if (!isMouseDown) return false - isMouseDown = false - var eventX = e.clientX || e.changedTouches[0].clientX - if (eventX == originX) return false - that.sliderContainer.removeClass('sliderContainer_active'); - that.trail = trail - var { - spliced, - verified - } = that.verify() - if (spliced && verified) { - that.sliderContainer.addClass('sliderContainer_success'); - if ($.isFunction(that.options.onSuccess)) that.options.onSuccess.call(that.$element); - } else { - that.sliderContainer.addClass('sliderContainer_fail'); - if ($.isFunction(that.options.onFail)) that.options.onFail.call(that.$element); - setTimeout(() => { - that.text.text(that.options.failedText); - that.reset(); - }, 1000) - } - }; - - this.slider.addEventListener('mousedown', handleDragStart); - this.slider.addEventListener('touchstart', handleDragStart); - document.addEventListener('mousemove', handleDragMove); - document.addEventListener('touchmove', handleDragMove); - document.addEventListener('mouseup', handleDragEnd); - document.addEventListener('touchend', handleDragEnd); - - document.addEventListener('mousedown', function() { return false; }); - document.addEventListener('touchstart', function() { return false; }); - }; - - _proto.verify = function () { - var sum = function (x, y) { return x + y; }; - var square = function (x) { return x * x; }; - var arr = this.trail // 拖动时y轴的移动距离 - var average = arr.reduce(sum) / arr.length; - var deviations = arr.map(function (x) { return x - average; }); - var stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length); - var left = parseInt(this.block.style.left); - return { - spliced: Math.abs(left - this.x) < 4, - verified: stddev !== 0, // 简单验证下拖动轨迹,为零时表示Y轴上下没有波动,可能非人为操作 - } - }; - - _proto.reset = function () { - this.sliderContainer.removeClass('sliderContainer_fail sliderContainer_success'); - this.slider.style.left = 0 - this.block.style.left = 0 - this.sliderMask.style.width = 0 - this.clean() - this.text.attr('data-text', this.text.text()); - this.text.text(this.options.loadingText); - this.img.setSrc(); - }; +(function ($) { + 'use strict'; + + var SliderCaptcha = function (element, options) { + this.$element = $(element); + this.options = $.extend({}, SliderCaptcha.DEFAULTS, options); + this.$element.css({ 'position': 'relative', 'width': this.options.width + 'px', 'margin': '0 auto' }); + this.init(); + }; + + SliderCaptcha.VERSION = '1.0'; + SliderCaptcha.Author = 'argo@163.com'; + SliderCaptcha.DEFAULTS = { + width: 280, // canvas宽度 + height: 155, // canvas高度 + PI: Math.PI, + sliderL: 42, // 滑块边长 + sliderR: 9, // 滑块半径 + offset: 5, // 容错偏差 + loadingText: '正在加载中...', + failedText: '再试一次', + barText: '向右滑动填充拼图', + repeatIcon: 'fa fa-repeat', + maxLoadCount: 3, + localImages: function () { + return 'images/Pic' + Math.round(Math.random() * 4) + '.jpg'; + } + }; + + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data('lgb.SliderCaptcha'); + var options = typeof option === 'object' && option; + + if (!data && /init|reset|verify/.test(option)) return; + if (!data) $this.data('lgb.SliderCaptcha', data = new SliderCaptcha(this, options)); + if (typeof option === 'string') data[option](); + }); + } + + $.fn.sliderCaptcha = Plugin; + $.fn.sliderCaptcha.Constructor = SliderCaptcha; + + var _proto = SliderCaptcha.prototype; + _proto.init = function () { + this.initDOM(); + this.initImg(); + this.bindEvents(); + }; + + _proto.initDOM = function () { + var createElement = function (tagName, className) { + var elment = document.createElement(tagName); + elment.className = className; + return elment; + }; + + var createCanvas = function (width, height) { + var canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + return canvas; + }; + + var canvas = createCanvas(this.options.width - 2, this.options.height) // 画布 + var block = canvas.cloneNode(true) // 滑块 + var sliderContainer = createElement('div', 'sliderContainer'); + var refreshIcon = createElement('i', 'refreshIcon ' + this.options.repeatIcon); + var sliderMask = createElement('div', 'sliderMask'); + var sliderbg = createElement('div', 'sliderbg'); + var slider = createElement('div', 'slider'); + var sliderIcon = createElement('i', 'fa fa-arrow-right sliderIcon'); + var text = createElement('span', 'sliderText'); + + block.className = 'block' + text.innerHTML = this.options.barText; + + var el = this.$element; + el.append($(canvas)); + el.append($(refreshIcon)); + el.append($(block)); + slider.appendChild(sliderIcon); + sliderMask.appendChild(slider); + sliderContainer.appendChild(sliderbg); + sliderContainer.appendChild(sliderMask); + sliderContainer.appendChild(text); + el.append($(sliderContainer)); + + Object.assign(this, { + canvas, + block, + sliderContainer: $(sliderContainer), + refreshIcon, + slider, + sliderMask, + sliderIcon, + text: $(text), + canvasCtx: canvas.getContext('2d'), + blockCtx: block.getContext('2d') + }) + }; + + _proto.initImg = function () { + var that = this; + var isIE = window.navigator.userAgent.indexOf('Trident') > -1; + var L = this.options.sliderL + this.options.sliderR * 2 + 3; // 滑块实际边长 + var drawImg = function (ctx, operation) { + var l = that.options.sliderL; + var r = that.options.sliderR; + var PI = that.options.PI; + var x = that.x; + var y = that.y; + ctx.beginPath() + ctx.moveTo(x, y) + ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI) + ctx.lineTo(x + l, y) + ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI) + ctx.lineTo(x + l, y + l) + ctx.lineTo(x, y + l) + ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true) + ctx.lineTo(x, y) + ctx.lineWidth = 2 + ctx.fillStyle = 'rgba(255, 255, 255, 0.7)' + ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)' + ctx.stroke() + ctx[operation]() + ctx.globalCompositeOperation = isIE ? 'xor' : 'overlay' + } + + var getRandomNumberByRange = function (start, end) { + return Math.round(Math.random() * (end - start) + start); + }; + var img = new Image(); + img.crossOrigin = "Anonymous"; + var loadCount = 0; + img.onload = function () { + // 随机创建滑块的位置 + that.x = getRandomNumberByRange(L + 10, that.options.width - (L + 10)); + that.y = getRandomNumberByRange(10 + that.options.sliderR * 2, that.options.height - (L + 10)); + drawImg(that.canvasCtx, 'fill'); + drawImg(that.blockCtx, 'clip'); + + that.canvasCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height); + that.blockCtx.drawImage(img, 0, 0, that.options.width - 2, that.options.height); + var y = that.y - that.options.sliderR * 2 - 1; + var ImageData = that.blockCtx.getImageData(that.x - 3, y, L, L); + that.block.width = L; + that.blockCtx.putImageData(ImageData, 0, y); + that.text.text(that.text.attr('data-text')); + }; + img.onerror = function () { + loadCount++; + if (window.location.protocol === 'file:') { + loadCount = that.options.maxLoadCount; + console.error("can't load pic resource file from File protocal. Please try http or https"); + } + if (loadCount >= that.options.maxLoadCount) { + that.text.text('加载失败').addClass('text-danger'); + return; + } + img.src = that.options.localImages(); + }; + img.setSrc = function () { + var src = ''; + loadCount = 0; + that.text.removeClass('text-danger'); + if ($.isFunction(that.options.setSrc)) src = that.options.setSrc(); + if (!src || src === '') src = 'https://picsum.photos/' + that.options.width + '/' + that.options.height + '/?image=' + Math.round(Math.random() * 20); + if (isIE) { // IE浏览器无法通过img.crossOrigin跨域,使用ajax获取图片blob然后转为dataURL显示 + var xhr = new XMLHttpRequest() + xhr.onloadend = function (e) { + var file = new FileReader(); // FileReader仅支持IE10+ + file.readAsDataURL(e.target.response); + file.onloadend = function (e) { + img.src = e.target.result; + } + } + xhr.open('GET', src); + xhr.responseType = 'blob'; + xhr.send(); + } else img.src = src; + }; + img.setSrc(); + this.text.attr('data-text', this.options.barText); + this.text.text(this.options.loadingText); + this.img = img + }; + + _proto.clean = function () { + this.canvasCtx.clearRect(0, 0, this.options.width, this.options.height); + this.blockCtx.clearRect(0, 0, this.options.width, this.options.height); + this.block.width = this.options.width; + }; + + _proto.bindEvents = function () { + var that = this; + this.$element.on('selectstart', function () { + return false; + }); + + $(this.refreshIcon).on('click', function () { + that.text.text(that.options.barText); + that.reset(); + if ($.isFunction(that.options.onRefresh)) that.options.onRefresh.call(that.$element); + }); + + var originX, originY, trail = [], + isMouseDown = false + + var handleDragStart = function (e) { + if (that.text.hasClass('text-danger')) return; + originX = e.clientX || e.touches[0].clientX; + originY = e.clientY || e.touches[0].clientY; + isMouseDown = true; + }; + + var handleDragMove = function (e) { + if (!isMouseDown) return false; + var eventX = e.clientX || e.touches[0].clientX; + var eventY = e.clientY || e.touches[0].clientY; + var moveX = eventX - originX; + var moveY = eventY - originY; + if (moveX < 0 || moveX + 40 > that.options.width) return false; + that.slider.style.left = (moveX - 1) + 'px'; + var blockLeft = (that.options.width - 40 - 20) / (that.options.width - 40) * moveX; + that.block.style.left = blockLeft + 'px'; + + that.sliderContainer.addClass('sliderContainer_active'); + that.sliderMask.style.width = (moveX + 4) + 'px'; + trail.push(moveY); + }; + + var handleDragEnd = function (e) { + if (!isMouseDown) return false + isMouseDown = false + var eventX = e.clientX || e.changedTouches[0].clientX + if (eventX == originX) return false + that.sliderContainer.removeClass('sliderContainer_active'); + that.trail = trail + var { + spliced, + verified + } = that.verify() + if (spliced && verified) { + that.sliderContainer.addClass('sliderContainer_success'); + if ($.isFunction(that.options.onSuccess)) that.options.onSuccess.call(that.$element); + } else { + that.sliderContainer.addClass('sliderContainer_fail'); + if ($.isFunction(that.options.onFail)) that.options.onFail.call(that.$element); + setTimeout(() => { + that.text.text(that.options.failedText); + that.reset(); + }, 1000); + } + }; + + this.slider.addEventListener('mousedown', handleDragStart); + this.slider.addEventListener('touchstart', handleDragStart); + document.addEventListener('mousemove', handleDragMove); + document.addEventListener('touchmove', handleDragMove); + document.addEventListener('mouseup', handleDragEnd); + document.addEventListener('touchend', handleDragEnd); + + document.addEventListener('mousedown', function () { return false; }); + document.addEventListener('touchstart', function () { return false; }); + }; + + _proto.verify = function () { + var sum = function (x, y) { return x + y; }; + var square = function (x) { return x * x; }; + var arr = this.trail // 拖动时y轴的移动距离 + var average = arr.reduce(sum) / arr.length; + var deviations = arr.map(function (x) { return x - average; }); + var stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length); + var left = parseInt(this.block.style.left); + return { + spliced: Math.abs(left - this.x) < this.options.offset, + verified: stddev !== 0, // 简单验证下拖动轨迹,为零时表示Y轴上下没有波动,可能非人为操作 + } + }; + + _proto.reset = function () { + this.sliderContainer.removeClass('sliderContainer_fail sliderContainer_success'); + this.slider.style.left = 0 + this.block.style.left = 0 + this.sliderMask.style.width = 0 + this.clean() + this.text.attr('data-text', this.text.text()); + this.text.text(this.options.loadingText); + this.img.setSrc(); + }; })(jQuery); \ No newline at end of file diff --git a/Bootstrap.DataAccess/Dict.cs b/Bootstrap.DataAccess/Dict.cs index ae20f704..46908bec 100644 --- a/Bootstrap.DataAccess/Dict.cs +++ b/Bootstrap.DataAccess/Dict.cs @@ -1,180 +1,186 @@ -using Bootstrap.Security; -using Bootstrap.Security.DataAccess; -using Longbow; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Bootstrap.DataAccess -{ - /// - /// - /// - public class Dict : BootstrapDict - { - ///- /// 删除字典中的数据 - /// - /// 需要删除的IDs - ///- public virtual bool Delete(IEnumerable value) - { - if (!value.Any()) return true; - var ids = string.Join(",", value); - string sql = $"where ID in ({ids})"; - DbManager.Create().Delete (sql); - return true; - } - - /// - /// 保存新建/更新的字典信息 - /// - /// - ///- public virtual bool Save(BootstrapDict dict) - { - if (dict.Category.Length > 50) dict.Category = dict.Category.Substring(0, 50); - if (dict.Name.Length > 50) dict.Name = dict.Name.Substring(0, 50); - if (dict.Code.Length > 50) dict.Code = dict.Code.Substring(0, 50); - - DbManager.Create().Save(dict); - return true; - } - - /// - /// 保存网站个性化设置 - /// - /// - ///- public virtual bool SaveSettings(BootstrapDict dict) - { - DbManager.Create().Update ("set Code = @Code where Category = @Category and Name = @Name", dict); - return true; - } - - /// - /// 获取字典分类名称 - /// - ///- public virtual IEnumerable RetrieveCategories() => DictHelper.RetrieveDicts().OrderBy(d => d.Category).Select(d => d.Category).Distinct(); - - /// - /// - /// - ///- public virtual string RetrieveWebTitle() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "网站标题" && d.Category == "网站设置" && d.Define == 0) ?? new BootstrapDict() { Code = "后台管理系统" }).Code; - - /// - /// - /// - ///- public virtual string RetrieveWebFooter() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "网站页脚" && d.Category == "网站设置" && d.Define == 0) ?? new BootstrapDict() { Code = "2016 © 通用后台管理系统" }).Code; - - /// - /// 获得系统中配置的可以使用的网站样式 - /// - ///- public virtual IEnumerable RetrieveThemes() => DictHelper.RetrieveDicts().Where(d => d.Category == "网站样式"); - - /// - /// 获得网站设置中的当前样式 - /// - ///- public virtual string RetrieveActiveTheme() - { - var theme = DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "使用样式" && d.Category == "当前样式" && d.Define == 0); - return theme == null ? string.Empty : (theme.Code.Equals("site.css", StringComparison.OrdinalIgnoreCase) ? string.Empty : theme.Code); - } - - /// - /// 获取头像路径 - /// - ///- public virtual string RetrieveIconFolderPath() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "头像路径" && d.Category == "头像地址" && d.Define == 0) ?? new BootstrapDict { Code = "~/images/uploader/" }).Code; - - /// - /// 获得默认的前台首页地址,默认为~/Home/Index - /// - /// - ///- public virtual string RetrieveHomeUrl(string appCode) - { - // https://gitee.com/LongbowEnterprise/dashboard/issues?id=IS0WK - var url = "~/Home/Index"; - var dicts = DictHelper.RetrieveDicts(); - if (appCode != "0") - { - var appUrl = dicts.FirstOrDefault(d => d.Name.Equals(appCode, StringComparison.OrdinalIgnoreCase) && d.Category == "应用首页" && d.Define == 0)?.Code; - if (!string.IsNullOrEmpty(appUrl)) - { - url = appUrl; - return url; - } - } - var defaultUrl = dicts.FirstOrDefault(d => d.Name == "前台首页" && d.Category == "网站设置" && d.Define == 0)?.Code; - if (!string.IsNullOrEmpty(defaultUrl)) url = defaultUrl; - return url; - } - - /// - /// - /// - ///- public virtual IEnumerable > RetrieveApps() => DictHelper.RetrieveDicts().Where(d => d.Category == "应用程序" && d.Define == 0).Select(d => new KeyValuePair (d.Code, d.Name)).OrderBy(d => d.Key); - - /// - /// 通过数据库获得所有字典表配置信息,缓存Key=DictHelper-RetrieveDicts - /// - ///- public virtual IEnumerable RetrieveDicts() => DbHelper.RetrieveDicts(); - - /// - /// 程序异常时长 默认1月 - /// - ///- public int RetrieveExceptionsLogPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "程序异常保留时长" && d.Define == 0)?.Code, 1); - - /// - /// 操作日志时长 默认12月 - /// - ///- public int RetrieveLogsPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "操作日志保留时长" && d.Define == 0)?.Code, 12); - - /// - /// 登录日志时长 默认12月 - /// - ///- public int RetrieveLoginLogsPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "登录日志保留时长" && d.Define == 0)?.Code, 12); - - /// - /// Cookie保存时长 默认7天 - /// - ///- public int RetrieveCookieExpiresPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "Cookie保留时长" && d.Define == 0)?.Code, 7); - - /// - /// 获得 IP地理位置 - /// - ///- public string RetrieveLocaleIPSvr() => DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "IP地理位置接口" && d.Define == 0)?.Code; - - /// - /// 获得 项目是否获取登录地点 默认为false - /// - /// 服务提供名称 - ///- public string RetrieveLocaleIPSvrUrl(string ipSvr) => DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == ipSvr && d.Define == 0)?.Code; - - /// - /// 获得 访问日志保留时长 默认为1个月 - /// - ///- public int RetrieveAccessLogPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "访问日志保留时长" && d.Define == 0)?.Code, 1); - - /// - /// 获得 是否为演示系统 默认为 false 不是演示系统 - /// - ///- public bool RetrieveSystemModel() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "演示系统" && d.Define == 0)?.Code, "0") == "1"; - } -} +using Bootstrap.Security; +using Bootstrap.Security.DataAccess; +using Longbow; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Bootstrap.DataAccess +{ + /// + /// + /// + public class Dict : BootstrapDict + { + ///+ /// 删除字典中的数据 + /// + /// 需要删除的IDs + ///+ public virtual bool Delete(IEnumerable value) + { + if (!value.Any()) return true; + var ids = string.Join(",", value); + string sql = $"where ID in ({ids})"; + DbManager.Create().Delete (sql); + return true; + } + + /// + /// 保存新建/更新的字典信息 + /// + /// + ///+ public virtual bool Save(BootstrapDict dict) + { + if (dict.Category.Length > 50) dict.Category = dict.Category.Substring(0, 50); + if (dict.Name.Length > 50) dict.Name = dict.Name.Substring(0, 50); + if (dict.Code.Length > 50) dict.Code = dict.Code.Substring(0, 50); + + DbManager.Create().Save(dict); + return true; + } + + /// + /// 保存网站个性化设置 + /// + /// + ///+ public virtual bool SaveSettings(BootstrapDict dict) + { + DbManager.Create().Update ("set Code = @Code where Category = @Category and Name = @Name", dict); + return true; + } + + /// + /// 获取字典分类名称 + /// + ///+ public virtual IEnumerable RetrieveCategories() => DictHelper.RetrieveDicts().OrderBy(d => d.Category).Select(d => d.Category).Distinct(); + + /// + /// + /// + ///+ public virtual string RetrieveWebTitle() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "网站标题" && d.Category == "网站设置" && d.Define == 0) ?? new BootstrapDict() { Code = "后台管理系统" }).Code; + + /// + /// + /// + ///+ public virtual string RetrieveWebFooter() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "网站页脚" && d.Category == "网站设置" && d.Define == 0) ?? new BootstrapDict() { Code = "2016 © 通用后台管理系统" }).Code; + + /// + /// 获得系统中配置的可以使用的网站样式 + /// + ///+ public virtual IEnumerable RetrieveThemes() => DictHelper.RetrieveDicts().Where(d => d.Category == "网站样式"); + + /// + /// 获得网站设置中的当前样式 + /// + ///+ public virtual string RetrieveActiveTheme() + { + var theme = DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "使用样式" && d.Category == "当前样式" && d.Define == 0); + return theme == null ? string.Empty : (theme.Code.Equals("site.css", StringComparison.OrdinalIgnoreCase) ? string.Empty : theme.Code); + } + + /// + /// 获取头像路径 + /// + ///+ public virtual string RetrieveIconFolderPath() => (DictHelper.RetrieveDicts().FirstOrDefault(d => d.Name == "头像路径" && d.Category == "头像地址" && d.Define == 0) ?? new BootstrapDict { Code = "~/images/uploader/" }).Code; + + /// + /// 获得默认的前台首页地址,默认为~/Home/Index + /// + /// + ///+ public virtual string RetrieveHomeUrl(string appCode) + { + // https://gitee.com/LongbowEnterprise/dashboard/issues?id=IS0WK + var url = "~/Home/Index"; + var dicts = DictHelper.RetrieveDicts(); + if (appCode != "0") + { + var appUrl = dicts.FirstOrDefault(d => d.Name.Equals(appCode, StringComparison.OrdinalIgnoreCase) && d.Category == "应用首页" && d.Define == 0)?.Code; + if (!string.IsNullOrEmpty(appUrl)) + { + url = appUrl; + return url; + } + } + var defaultUrl = dicts.FirstOrDefault(d => d.Name == "前台首页" && d.Category == "网站设置" && d.Define == 0)?.Code; + if (!string.IsNullOrEmpty(defaultUrl)) url = defaultUrl; + return url; + } + + /// + /// + /// + ///+ public virtual IEnumerable > RetrieveApps() => DictHelper.RetrieveDicts().Where(d => d.Category == "应用程序" && d.Define == 0).Select(d => new KeyValuePair (d.Code, d.Name)).OrderBy(d => d.Key); + + /// + /// 通过数据库获得所有字典表配置信息,缓存Key=DictHelper-RetrieveDicts + /// + ///+ public virtual IEnumerable RetrieveDicts() => DbHelper.RetrieveDicts(); + + /// + /// 程序异常时长 默认1月 + /// + ///+ public int RetrieveExceptionsLogPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "程序异常保留时长" && d.Define == 0)?.Code, 1); + + /// + /// 操作日志时长 默认12月 + /// + ///+ public int RetrieveLogsPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "操作日志保留时长" && d.Define == 0)?.Code, 12); + + /// + /// 登录日志时长 默认12月 + /// + ///+ public int RetrieveLoginLogsPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "登录日志保留时长" && d.Define == 0)?.Code, 12); + + /// + /// Cookie保存时长 默认7天 + /// + ///+ public int RetrieveCookieExpiresPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "Cookie保留时长" && d.Define == 0)?.Code, 7); + + /// + /// 获得 IP地理位置 + /// + ///+ public string RetrieveLocaleIPSvr() => DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "IP地理位置接口" && d.Define == 0)?.Code; + + /// + /// 获得 项目是否获取登录地点 默认为false + /// + /// 服务提供名称 + ///+ public string RetrieveLocaleIPSvrUrl(string ipSvr) => DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == ipSvr && d.Define == 0)?.Code; + + /// + /// 获得 访问日志保留时长 默认为1个月 + /// + ///+ public int RetrieveAccessLogPeriod() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "访问日志保留时长" && d.Define == 0)?.Code, 1); + + /// + /// 获得 是否为演示系统 默认为 false 不是演示系统 + /// + ///+ public bool RetrieveSystemModel() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "演示系统" && d.Define == 0)?.Code, "0") == "1"; + + /// + /// 获得 验证码图床地址 + /// + ///+ public string RetrieveImagesLibUrl() => LgbConvert.ReadValue(DictHelper.RetrieveDicts().FirstOrDefault(d => d.Category == "系统设置" && d.Name == "验证码图床" && d.Define == 0)?.Code, "https://longbow-1258823021.cos.ap-shanghai.myqcloud.com/pic/280/150/"); + } +} diff --git a/Bootstrap.DataAccess/Helper/DictHelper.cs b/Bootstrap.DataAccess/Helper/DictHelper.cs index 93ae369f..0f704c63 100644 --- a/Bootstrap.DataAccess/Helper/DictHelper.cs +++ b/Bootstrap.DataAccess/Helper/DictHelper.cs @@ -200,5 +200,11 @@ namespace Bootstrap.DataAccess /// /// public static bool RetrieveSystemModel() => DbContextManager.Create ().RetrieveSystemModel(); + + /// + /// 获得验证码图床地址 + /// + ///+ public static string RetrieveImagesLibUrl() => DbContextManager.Create ().RetrieveImagesLibUrl(); } } diff --git a/DatabaseScripts/InitData.sql b/DatabaseScripts/InitData.sql index 836f9c2d..cf6e47d4 100644 --- a/DatabaseScripts/InitData.sql +++ b/DatabaseScripts/InitData.sql @@ -44,6 +44,7 @@ INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设 INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设置', N'BaiDuIPSvr', 'http://api.map.baidu.com/location/ip?ak=6lvVPMDlm2gjLpU0aiqPsHXi2OiwGQRj&ip=', 0) INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设置', N'JuheIPSvr', 'http://apis.juhe.cn/ip/ipNew?key=f57102d1b9fadd3f4a1c29072d0c0206&ip=', 0) INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设置', N'演示系统', '0', 0) +INSERT [dbo].[Dicts] ([Category], [Name], [Code], [Define]) VALUES (N'系统设置', N'验证码图床', 'https://longbow-1258823021.cos.ap-shanghai.myqcloud.com/pic/280/150/', 0) DELETE FROM Navigations Where Category = N'0' INSERT [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, N'后台管理', 10, N'fa fa-gear', N'~/Admin/Index', N'0') diff --git a/DatabaseScripts/MongoDB/BootstrapAdmin.Dicts.json b/DatabaseScripts/MongoDB/BootstrapAdmin.Dicts.json index 83a3db13..9cf9fbf8 100644 --- a/DatabaseScripts/MongoDB/BootstrapAdmin.Dicts.json +++ b/DatabaseScripts/MongoDB/BootstrapAdmin.Dicts.json @@ -341,5 +341,12 @@ "Name": "演示系统", "Code": "0", "Define": NumberInt(0) + }, + { + "_id": ObjectId("5bd6c73d5fa31256f77e4a49"), + "Category": "系统设置", + "Name": "验证码图床", + "Code": "https://longbow-1258823021.cos.ap-shanghai.myqcloud.com/pic/280/150/", + "Define": NumberInt(0) } ] \ No newline at end of file diff --git a/DatabaseScripts/MySQL/initData.sql b/DatabaseScripts/MySQL/initData.sql index e4ba462a..348e6142 100644 --- a/DatabaseScripts/MySQL/initData.sql +++ b/DatabaseScripts/MySQL/initData.sql @@ -41,6 +41,7 @@ INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', 'IP地 INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', 'BaiDuIPSvr', 'http://api.map.baidu.com/location/ip?ak=6lvVPMDlm2gjLpU0aiqPsHXi2OiwGQRj&ip=', 0); INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', 'JuheIPSvr', 'http://apis.juhe.cn/ip/ipNew?key=f57102d1b9fadd3f4a1c29072d0c0206&ip=', 0); INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '演示系统', '0', 0); +INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '验证码图床', 'https://longbow-1258823021.cos.ap-shanghai.myqcloud.com/pic/280/150/', 0); DELETE FROM Navigations Where Category = '0'; INSERT INTO Navigations (ParentId, Name, `Order`, Icon, Url, Category) VALUES (0, '后台管理', 10, 'fa fa-gear', '~/Admin/Index', '0'); diff --git a/DatabaseScripts/Postgresql/initData.sql b/DatabaseScripts/Postgresql/initData.sql index e82d2ca7..0489a044 100644 --- a/DatabaseScripts/Postgresql/initData.sql +++ b/DatabaseScripts/Postgresql/initData.sql @@ -40,6 +40,7 @@ INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', 'IP地 INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', 'BaiDuIPSvr', 'http://api.map.baidu.com/location/ip?ak=6lvVPMDlm2gjLpU0aiqPsHXi2OiwGQRj&ip=', 0); INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', 'JuheIPSvr', 'http://apis.juhe.cn/ip/ipNew?key=f57102d1b9fadd3f4a1c29072d0c0206&ip=', 0); INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '演示系统', '0', 0); +INSERT INTO Dicts (Category, Name, Code, Define) VALUES ('系统设置', '验证码图床', 'https://longbow-1258823021.cos.ap-shanghai.myqcloud.com/pic/280/150/', 0); DELETE FROM Navigations Where Category = '0'; INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '后台管理', 10, 'fa fa-gear', '~/Admin/Index', '0'); diff --git a/DatabaseScripts/SQLite/InitData.sql b/DatabaseScripts/SQLite/InitData.sql index d05ec895..d9f71359 100644 --- a/DatabaseScripts/SQLite/InitData.sql +++ b/DatabaseScripts/SQLite/InitData.sql @@ -39,6 +39,7 @@ INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置 INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置', 'BaiDuIPSvr', 'http://api.map.baidu.com/location/ip?ak=6lvVPMDlm2gjLpU0aiqPsHXi2OiwGQRj&ip=', 0); INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置', 'JuheIPSvr', 'http://apis.juhe.cn/ip/ipNew?key=f57102d1b9fadd3f4a1c29072d0c0206&ip=', 0); INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置', '演示系统', '0', 0); +INSERT INTO [Dicts] ([Category], [Name], [Code], [Define]) VALUES ('系统设置', '验证码图床', 'https://longbow-1258823021.cos.ap-shanghai.myqcloud.com/pic/280/150/', 0); DELETE FROM Navigations Where Category = '0'; INSERT INTO [Navigations] ([ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (0, '后台管理', 10, 'fa fa-gear', '~/Admin/Index', '0');