From 41d3763b5717519b39399512bda66182c54c69b6 Mon Sep 17 00:00:00 2001 From: eson <474420502@qq.com> Date: Mon, 27 Jul 2020 00:35:41 +0800 Subject: [PATCH 1/4] TODO: finish extractor data --- crx/0.1.2_0.crx | Bin 0 -> 26871 bytes crx/0.1.2_0.pem | 28 ++++ sql/remake_database.sh | 10 ++ store.go | 3 +- tasks/twitch/twitch_task1/task_twitch.go | 2 +- tasks/twitch/twitch_task2/task_twitch.go | 160 +++++++++++++---------- utils.go | 9 +- 7 files changed, 142 insertions(+), 70 deletions(-) create mode 100644 crx/0.1.2_0.crx create mode 100644 crx/0.1.2_0.pem create mode 100644 sql/remake_database.sh diff --git a/crx/0.1.2_0.crx b/crx/0.1.2_0.crx new file mode 100644 index 0000000000000000000000000000000000000000..54ac5ce1ccac8a5f21ed789eacd2a182647ecdf0 GIT binary patch literal 26871 zcma&N18}8Xvo^eA+nLz5?TKyMn%K4`wr$%J+fF9Q#J2h8dEWD#I`8wH_p5)^?!Bt+ z>U-7RtGlo6)!j?jfr$kK004*r0|3aCpwPv@3;{qy3~=C3R3YLak8nUhKwton03Zaw z*K=s#03aYhE1W+O?Bmt^CZ*N4%8s5w{yFbo`H!zXZajNtOnzp$c|ffK`0j?Qe2b4; zqbI*t>%+AsYv+O^%pkfH96U2Zos@EPvbRnGfF=)EPIa?_dy%7c4}S{owIlv90jdEr z%N44Vr~(D~wxty3`Izd9_s6!p2iigOP^}DDXcLHqW~WBpLKT3@&{rdak%WJ8e=cKUs?gM`Rt%SwZPAfbvsWE?t&;<5+8Xm zF^tzOxWFJl03c*P;QAHADwm^o+1e#NagLvIV4&tw9nqPfNJ|w>N*{Be-t!A+=@ci;>mLn+JZ2RE4p;@0?@bbJY>i`YYmSGDRSy3quB9Lge|ZSO z?feV*H*34jnj}gyb5<{TT)GPqzn7~URpwIJbQVg!vQEE>Zt8t?sSFKN)KMe@sfcVs z(}boRKb}Re!?68FMPI8=z{{zofHF=a?Rvgc)19lmW06a~j~3e!XMXW6qL8!z`rW%rlQ%xczVFJFG*z7!y5~zt z0<$=nDJt#_p;{Z(rwHxcHOk4cJ{ZP5gBCPvlufGniv$(^hupz@{E|4kx)9J}BX)&m zL4C3A@d2dL{4@jWJFpV_6od0F@O){G0rowtl7Oz=)GL}u&?-=)&;fV^+UV`mG?~;u zjI$J#f2qA;NBnJ*6K2R%L_cKFZ2h$vZHn?&L))QIS&6;R^Z4et##RT=}?A3+UcV3P)D3DKc3Gn0&y zs3csZRCzEe?#8fift(v+T7%<|1$^1Q{zOQax)>9s*}N+tZ91%~RvJa-8+xqklql8~ z*{Ouz19ciK?{8H56Qepl=IIEyw|P1r$4NVzAWq_p!sC`2e3(t0`hg%0%Nr_M+rQ3$ z8EgX~Knm}hms5;Tf}kEn?kQI`mn!-YSQ-WPhC3M>&PPEn&uQsgTN3`DvR=N@1079s z9TeC;7pz92Up`Ft)`B~=qCsH#qcJ`^b>=v0i9Hv=aWOajUe1y3OuJW?5!qVT?eAPZ z?DDTx%Q^Hh&P$r*;BG z2d>Z2MrkvhIlO^P9zvmFZL2|Dna&7#Rhcf~z#djr=tP$M+IXly)ML~w&B&y-B{AsUs^ z(<8&7b8;||3$lat@Z0YM2`*!~UlKv9*b1TY-+Kq$kI#=MaFiK(yyw-0!a94JsY1T#b;xZlS?ku0WKqJ~p{{OLUI3e(GD*BC#byEzRJ>Bgzky~ey1 zN(56cc9+sFJfL=3+1o?M^`?4{>7nJ`!K)=4NEez>F0RNc> z?2E_Pz{%j>m{5XW4#JcIkP=6A%U4D@1n2LJ>5WkM)9KS4@7DWRO*C@41nlk-0(y<33V;)H#&Pd8UF|(K4nMKlaMa6-?yV&;ndfRf9HcXPn;7+uxK(J319RN?ywc|n8P z1V_fh#l+Fs*OM?*xUwi!%CroYKYKTZ3%X3ZqR3fFQ)^(@?+B~&SY?|(%cvYg*;Ho7 z5J78>8APh)afsP1F$$aJDVls86D$365|?BPlno{n>X}^>G`XYa;F!(I;#Y&;Bg~eH zxSkF5>XVaU=65XCY6lMn1mn&Xzk?@jfQ>%^9MQ8xYrKgPo1ZziGf<*qy1Q&rkY=-L}yGQv+;l>}*z?+iTjHi%7l?OjPS`?)$RZ zvYI8TWcFcF`h;fkNIdi2^U?kbbRInLUS3F1P($T}aC~uQa5M?>)jDk-!WKh&;PgAM zSc?Z{Subg;VZh+%Q1o8F9v3cJkP;D8H?JHBp`ZzMDlU++Bk+S)L9gKwb&%>QVZNJn zyI0h9(^@`MBvY_RJ5MTL9K?9v@1%*6qe5JXqu0X*`a(aM`>$CR@>G0RAY(A0l35Ub zs_}jY6)$0r5~I_kjMx~ol_WZaG@3e_C(9DMgN1b^t+Y-`IWW5nyF;1vD6O(iNfjjL z6r0*@L>i*Uw#{;qdctG)2bZVl8-%a*IfWD3wa=2<9%=#+n& zg}vwPaXY+?>rj@!@Skh!gPqq=@z_G{wgk$l-=ZsJU=9|2(wOyNt0~4!{P_wdMUa)E zhm8~A7*Gr8JUZKTYSd2AHX+Pw`}S#H%nQBWyZ_YF>AC3NLK9^CN_)MYd5>>WNz?oR zCS$&;pp;)OFr8HqvlUlfv=;rMW_*ZcURg4ZT6z*eB7nvZJUtoBKZQD+MkpI@unTS{ zocVK8P{HS^RM&A{YQeJ_5BN4eqg>4VrX63dUMcZ4OVS)+f^BjWKgR3MUNLDDMW$;s z2R>K<@^rkAfTkrj{GeEh;*ObQGUwOtoA2(qok{T4etb4;$sgLc&DCwOSSW;q~~blU}5j{f7##{+keCPU*`HZR9k$#M)wHZBk_vioAH`6BEu`WxN<1p|f#MpkAHcFwlObmmSr)(r|y*RJs4u=Xk= z6r+=MyZiP2bI{OiSY_dqE^KXOq~Xw`SmC0BWu(oLMWhz(=#nmMFZvR-^@VSVk_<2- zbh30~G!zOHbdt>~bMy0ZQ`1u8(#zvi;KzO=21;p}3W+%x5oHr%_?B!lTwxXe@KjNH zGo)HyZp;H70QhUm{>RV!7ifJU(WIJ`-8u(iH^hjqzPotoLR{8>6)J1zVE($W-@}~E zqarF8?JS#C+CqF{G{L>^Wt2FtO^ZK5$2ZV8k*UZnFXn#hRzjZX(I}pa;zP4TvnwRK zpgKirb!}9tA5UXMH|9aqQADF-M@?Zed6_|nimk5NqrtT?qDfS1LQ>SR6VHm7hUIhb zim8?Lhfg@dMO+vW-PWt1SPb9J{1c;5h+9$4;`-3T`nG`ba0b|c`LZYn=+>T@$H5Gy zQMX1&UDpP*80Fx?uxj0W#9kCM|L{?jRqkp$T)%5A@sVeqbLQ2sF+)$IC;Ghi@$MO_ zDvvqMfSF*(Ahgb(Y(_@199X=lYLX{1R4SkmPH8$%q7Brej}aF7hFj0Zv-P2;Rj5Gz zntvVS0DS=JBWYNTk}sM}H)|x78Br})wnGX*K+K`TInB&RA~6Oz8;f2M*HItI2&?$n z1Ja-EpCD9ZNSGu(Iyi_F2OmG*9jc7s4&4Th(8SD;XdxyiX8SfR8haXUL36?-?@EI()`l~w7;ALsovI>1@VApO zakYfUwFT}glZ&oKzKeJyBxR*3&>;q$p>VKdC5clD4s~o)5(oK&0~S ziq{zHbTO$4uo4jRhO2>W!`{(K?IQGm7IYpLFP`)pO7M<9KGYeZkx|vA{kg1zz*ovj z@7ua$S)oOobp*ypFp`cw23f9kC?j+YfzH4egjHB_9)+XHpQ@`53c?*)@`HfjhK@=r ztt5L&VFs^Amwcux{6khf@&jSok@$mh8=8dxJ)T0$dQusR)sbXHorbvyS ze_Ovj)sbi*+EmdP?zt?nFBZl7@Jef^J;!;|{Bmk*(JVuwg zf)RkoJT2eCZFqP(4NM0a@=y1|`>r0*il@P+RKy?BJ!7ByYNeihtw;2mo&(+I8raM} zp4wrZ4&gsyhucLYduMQRs+Gjc{UtVSG8UZ}h6KZ<(O4eXHBy*b%k6<)pFsbP-xfJ< zoEm?D(H9Woeu2^70Q(R8wy?D{G5YIt8>}khxXy;i`@IMF7a=fhnq-Zsid_0=9&_}3 z8F$x6IxJ{4Nz`*5aIST9{^zES-%hABH-r|!6`sqZL0x1Qi#6%u?ogsiTs? z3K$9!cMRq_ao;|-Hdi+Co2r)50b)kEJ+|-o4z)TpJK{LYyOI_JSn3oR_(w%=J7t4> zp?=@xmcFZr0in9SwGKAfNUUrc-N=S}Fk_b~FgZGxPCWv?z1NCho9SWMv)9zqD$Y+$ zUHzql-7KedKbwLsm;HNq-a{S5oaDgu3~YO@J-gJON9?;;u)%xd?q~N{-=$&CGYmq{3Rp9%v_?tM%c5A<@M^Pa77bgI1WXGX?6^O#RfaE zvu2v*RH1!?-|Y36a{pY0@+KR9e~LYQtLw-F%S0X`kLM)i7KphIkJ2Q0UYb3q6a>>pOE#?m*=0R3ZV zlQyb3sgq)!tBu*7;(K=m&dj~XoTw(BLT}FLs3&qiN^xar{lp|=Pa|1-+u7g_9A}EG4R6~$qBQJuZqU{WG36o%vRyL%02b=EWgmJU4Y8=qNENcG zA{bc=T$NrULPuPzu_Ukth(J>qH$y#Ya*1fWd#4hLz5965=uK8V#wCAxMH`6NE=fTk z%f=hVUpacKSi&)a9-&ifT(H_X(rZ?cKAMLGf;RxGycCI&lc(COjg3(pgoX-Zj;+G( ziOVCp`7MpG%0vr#+yI#S^63wC40ZBPf3wiuYYvN)X{w>JW)2noB`CWHI`py_(5VzV^S#&yseOaoWhdO3&!%j7)x0tPSpLsG#Z#9gK>01+{rw+MV zL4ENqc&F&HdfcFwB)WyI3qkYNN8Hl*LESY$YxNWN4mLN-{)?9)y4GcY9x|7+{p$SB z_&sD>#tQq}8LRH!tX;viy7Na(JgNFb44_e~138X!f84{jOi#RGk4?NXjtPY~2u|1c z{IKp;Pv1~Vcug~5XS~ZhCv|7E^r!Z1Q!MuBZ_l3BZ0lTkMtQZDN7?qYJPW%{uF8v2 z*^cZ`;~|7V@*1@Ve(-EC^O>Y!>O~h6w`Xe9`8O&O1of@q*FD><{KixP zXSlaY$hW;waL{<7X_cG8>gvlT3=t9j!7V2Cf3fdmjQ;5R0=%v-Li%@h77jXlTQi_8P@&gwdD-u9 z(AZyxL;#$GxQOD{%{XYQWE-003x^govQBx&L{Zjk%Tz=J4lqmxN`5kc?e} zVMWXi8CTOWO_^e%3L@Ep0g9G^lM*UB=8paegy6uK6M-sHNj@6*VwKN`lqiPC57}m- zb|)*LUkFrSvyyrA7T>pQ*FEw0Q!@rM5=B(En>V*l~rU04eJtBJe$E0Awj)FSU_`UM?6eF22St!mbSKfR4XSZ=$xIL z+^DFiE&$t9s#tz}m`-?rF!QauyE_KI#|YLVfZx>A6uLzG6mTh>Y8==_Krny=5Nq-* zVI6aejWnsDunhp1b}!-i!ZL2=mJ53x94?=#sKoh?hJl&9VAXbgv+1QrC{)C6p`+Ol z?o}vknC`Wpmb`7|>L}IH^L?DzGY%YhyII_l0A$Rf!GgbwIK_s6_y4(S@qj{7kciLy z-QN0iLfp_G2WaIp(?z^prja;gJ*bJIfCdHD3P0lT8&1Hql&smqt3DLrS|KQPiAihCS2P7(F8b3i0qV?P>!^CIC&pc$ma|4{^l@1R-YN0l0(h z&A=xbOoKiVuyR%ODVYr)Qjys(03aR}4cFM&t{kdN=wZ!iajY6bs{s9*a0YyS71i<= zGvEt$Vl5|(`h-6xC*K4cWAQe*=jI%;6f~$wNu(hUL`l~`Oy3WjIZ2P*3+h!RM`Ta< zl@jseXvh1Fe0(#IetqqoAdv^YUmV;dxV-fFzR|+DPhvQq3_@0b`PEIe&VBHnVVyb^ zaySn7HiUg$?@heP*RgD?x*`Mk>Q%4UE#u4{mRwWIj*SQ>T8w_Yegk|P((l>J%7!0= z%Te|)&k=7LVq_C0dVnYW>NV%x{q-S2=q68IJW{NH+*qSKI8E+PPL=~4h0d2r9#)j= z@@OgDVgugATu^3O_O9QO?_Txf8k_l2t*zG6<-Sv(rsH5^a}h|)*%FO;m!twqI)OXb z!`ZFg%zf9r1b|>T9CQJ)i4UeNY|i0`Bl`Yafr%<;raof<4#SQ>V|}tA!2?SGcPr=K zbf6@UGIBYqb)9dBe(U${;Iiz)yRVUp6+LmZTF$kIuutGtR^B3sSG05w=h+#KYF2A- zB6p!^T^;}wwkLB)Q(M{A-;+=+-vHRl_67Dm(^3aA)|Z=I zO>`+0-ys!1a?``8Zb#Bg3VaQh!j7a#ke`2vahr@KQYsDM_yP}7M~7DFcu#%752?(_V=0G`0tk^+ANUb)4OO#lE~{4cqlqP9d&Y=7#Mx1pEZXj1`ziWVTaNaZcO1?6Gw2v4--SKJ1W^ ze1`GUF2J79PD)96G!_*NHZ@qzJ^B0#Gwnqc@bnLqsk6i>b3(#@fdG(rb(NHup?V*e z?#ctLfUZ2c=t0z>1W4;`Oi4hQF?x3ZkN^r=S{aBdq;`{m^N__fC?|Mzg~T|(ix#ad zQc9Y84q|?F4&r(hx*CvQ*oy|Ob-dI-=f~>7!7f5`V-%vuPkxQc{dEV1^|+ z2vPL}J0L8bxk#Jw^-N>-r#qRS^~R2e)B1$F;GXaM-LW@TdNZK+H*dGdfa$v%PqsEd zCWGCs8`KG1P*fpa060W{94^3LKroy{zUo0ya&V{2ohBPv4d;g$(b!U!^#it#*^ zlk>ZO+Z9GMjnn0FQ?p>r#KdGb^%=z!Z)=_VnpdrXjWVfxg^F1suEUpXJyf>@gA8&Vl zKK*rOztrWukbcLGG~Y@4Hd8FD&gsK%q($0;6DZMl!xtvC-b2AK-+?wt8iIq1dCf@9 zyL2yM6vwszBs^}W=mKT{7MTWW06*MMkxmZ~MqkE-KGM7lx4P!*CiuX5HgR?kOCwG>1pLxY+Ok=c9o&t{pd1cr42?=@yUr%nUVIUkFV zFfBxF`&L07FkF>v=2DJPB&3IccVNFd?Uc?y1?~aJzn0Wm1~$y@ad@1EtRLGdv@>pmjHk(#;dALfnIL0hTaID z^>>rrnI_>-T|h4XOH3IhUACEsG~_iSk`3b=8x|`7U{6K5&k9w!w4Uldnimi-jJ$aB z`VQwW(Az(e0Q8om@3^k!&(TKRP+tw0*#ash5xEkVkPx(swjC&z$!MmEU;^*$01$aw zBvgK->7KL{&{a!{XhoLG7%+8wbDo!$hRV#2D5Q^KUVtF;Ut0tA2nE$d$@BqjFUAimQ3 z_}G?6GZ7_x4}iIG&gr~%1If{FFp-8E&c)$!wi4Xl-ri)}(vh9E9)8pji9uh@<9=g2 zY*RbDJBlHM!@`fQWDk9-R+G)U9$RhU2)J`n)J|8^c~4G~-R(iNXi;1sKqdD0;qKxh z<$K^fFPx{e8aLtwK+(TBc@--K4{}$!=!2V1A)xGE;&32xb4%aK>%0dh@qq%K-hCuQq$*Ln!Gh34 zS1p@Lkv|KXn_W`Y&$~eh@WbDem*Hg*XQQIOv0pT4who_O&CSg@QSQt1aH^sf<&>9K zcXKGB7FB%>xmPFN^y1O6u`%lKW=H$~8m&;D0NPoZoO7UAh5zidE`(t#>c0wgRbTWE zr^U$jx6`TuQvCQ|oEGBOnuvcpE&SV00{{TX=`W|n5j_~+C1oUtI_Ue@Ju3W0@kSs8 zEyztcC`JN~B(mBBO&PCBGtf8XvYv>(ra^i30Yr%8`703|30BjpiA`t^3lH)qyO9yW z07>%Z4f|oHrzz&s1(Kf^AOEW7_Ui|DEjbZ10ny>2<$bG~S;XKDJ`(4Xp_J9dc@>x! zJRrV*qC(LAff~|*h{Ake%@T$CDqY3e;juEI2W9FNlg8l z6SImlFO!Ou4L#`g=;I+$TG#l#4=hv|I9r&=!N;r5Z%xma)^0xFSlJSMKi=GX!bla7 z7dF6Cigb1GP*ijORdL$nMasB|R>h($&$O2P)H_&qlp`JT@oUTg(R^sxf+iU(J$k== zSwD5s7;`O*eiY;I51by3LlF@^ZwtTmI>z+fUA4e;pUX}VoC~+@=HHYY|5?CkLT%TU zUv)T>FZzdonVJ3;un9=|+y5e9g0D3R{uZ#KhsPZN07CPZfYpP~leesJzM>NT$Ia37 z-zwias?rIPEX$CzQH}C{7i0m&>Z1!$K&&fS1J!i z1kWW|S_g~gCL_~|Y}7YUckFI*@{#CAH*hDc4nMrI*moa#c00B{Zh)}ccL|e9q^GBQ z05~8En}-^gDxST33|w5;!V2~QsF8y{)3*;=Ruz^``B6z6Yx}{Bc*kPHY00LZ4y`S!zHLlMeMbD`cYnUkS>qxCl zzdzpYo0{Y{)wRCmlrHM7E?eV8jisffjrNH_Ama|mjHq|%rdO)!=#vuwmnc})DFvLi zzg9L~vSCM?K?nDF%OVV7l`ZpUR;ucm?h0fJ?2QN~jY)>~vA3+Bw^TNL_s;+X5VTI# zEm0XwG)HbBgX-Z`tCoPiB#m5q6*-6q9zkVgXY*NC@m43cdrFOvocndU?T?B2mn4p0 zJWK93)$Rlf8OT%K$Aw9Ugku`vWJwk^dxI+@di9L29s1|mOelcm34f=&7cbcX5bcn( z1NBcHxa+gayFX2&<#1mI5QJf4i;=g1d1_WI9hen;lcQW*6xe|`W-rO}TaE3&>$D~Xd_a-H>1D>pHZBj*c2Iw=Ua2x+&vA4@v%F)5Z z-)c)zqDuPERafUQjT!|Z?{jjhSd=st*v>`(hu}rh0K>CuS?7Oe;Ch)G3=jXLrP_CJ zclPo5&?s7f>D{*y>UO~)j|1}K$32|!6c$dYQrrRvL-SR$V*9>vaA`vCPESrwnl!Aw z`WsnK#OfuUw!3Ot`N~-uqMXXf`ObfwFdfaInO8b6Nu z`>V;p!@eceKP>2O@uRUT(9_a3t*8@dDePg6JPq-*$IFIZfEqkabIa49zb-E?&+~GQ z7-R1{tX_)lf>+bOf!LLE2CDNx{guV|561(T98ZjS%3*s?Vg1-Oh@wqp4RLj3rEIjHD(DQ!5KbAmdChJ(Y%Tg7C&;tHNmz zhzZG#v2Ehrm52zxo0gO-h1RYVUTMX2x18W{Azz|EIfmdey~5e zBRJ%6nt}rI6u1+UxbvLaXy6aKe>h#OreN-lr_gx5mU2G(26ueB%0Y^Bg-Yaa)4{o8 zd^43f*jw+>4JDtMjJ`c(VS_zZ+I523i0g}FsdN9yitdK#m*0QJxpZ$NKv!?H{y?XTXB(5@$9BA?hJ=T2hSaD96EtP!dXYGk$6|k5krK=b zY~gT#w)e5&)BYyuM~|kfez}bGj!3$}zD>BZbBtA0zNM~?U^G!xS?L5dj{TnCswmo* zE=zL9^gVzG9i;4RaZ4pd^fmiiPqJ6c5UW9w51;W?oY$>^Yaw&dgEZT%1=gxoj(VX7ZCfDxZHuR(O3AoN35%zxvIUX zq(erljwc`aUXqUz<=tkDzUi7Fq4YZ7?oIO?pLgKOXOP-WzQ?DiyCpJunrYiAhRfgMwM?Z1 z9*`!66FzP~-&aO|*OaQ%chU@o0fxD97MIpMWtJWJ#p({b$W|_kmI?q%7R;XwzkXD^ zR4v;H-7mfP$)1b^G;p^lTd+5rD%IV~`x(HnNrIEX_G=JYWW2S~b;o+RiyMED8gTBsV-|euB z!H1YQIOhsMe-~ICo zX@v2G!kqy-xS3eAQGpDRtPDL!Rbr!}csOcaLu05#NF~bmRVpgwczF@4jAP=+5@#ab zd4q_NxALiBVd}yjPP0X9v&5_@2OrMeeX=W(ow#a*4l}|bj=ihc*KN9aHNxUVoC3z? zcXn#}%S0&1mN|nBXon~J4kF=-aqlmkti;sI%lErGw@d!F&X(Jt7f6Sw&E6mw;{JZq z>)(|zdu1>-v?UDrakZu}>3=v>rKEEgCTlXlL^shiq#(3sVpYgMmANYM@NBP)~fg6+NHwv=UZyA7%Q5E5<=75h!t0I&^YC( zsIV)rBdz-gE19_lr}>zdsfw3OQ~Rp3`nv9q!b-9@ruFtV3m_Y-jpr8!Z;!R+vqfh` zTifa;_V^q5)f+4@!nRRX-sR*(63I;MDU$Or<(m86B$k4@lQNQpz}gn3>D|-uAi}Mt z=8@mXErv)@>}`XxMM$D&bY7F~5ju#%RQNX@IeJ*>z&WiVIjNa@kwB8mWG08+HWATJ zm}K>&Fi>-IxV9~&E_+*5q+_s6e%WgD;m7mBOye&xwu201+#aB|trBx@MDvZp{gD#{}WiN#YnezqH>6}(^LP5Gp zm$TWc&a>#2iiKnkHhmclDkU`=<+mLy+-gmN&LP;^Fc;0-TicW}RzVSE3MtNGuc&Bs zlx~y^B8Uk^|LRz?#~hhA^`MLp!|r&iIIZPCsfg=jHc8X)=eWdLdBNc~=H;=E-d7Q}I?cU|!NyRu ziyjV(L(I8fQVx~Za}HW99o;L(K^{{-Jst0T>HG2r2}yR0hq0u{f{xTEpfPo&EIkQ}q4@5T%)*0*0PvHRtx*=Efx1gT@yeP#f^;fH5iH%R=w}hKOgVv*~E$~+Si&fAC6{;h3G*Kyb}#eitQ|T3RIZ7hXqg- zz|z=A`gi?{wHkMN5kQygJc4BJJi38Ijk_cC9_fl=Ta~EM&e=TGV|o#r4A`$3WkHyq zscnX91^`b_6rl(9N;ss_J^fJzxSW=j#$=@N2S>wP)%16>fHw_nI;e?>3E6OAfOj39 zEe+m%YpVGLE3e`YWy4&pO8M-5%T6wDBYJdg04t;NcM-JfiH_fP$0xjju=UD~FUht> z+1U!DhvYT8Bye-v?|)~}JR1)zf|y&#%+lYjaAnAXj^=$e@=XMudBsy(>J69F~U`QTbu{@GQ)ujIAuJj_@d;9kn`KeKS9yuYl{B?QU& za#iv{?9_SLW$1g^z~4J|L(omWi&LW4d#_nUh+OPwGo#$1#?u~(PAw@UCWs0wq*c;L z{BCME)Rk}TNEFX5!o$OJ$A01y<={_v{f1wwVC!o=zIH_Y%Vksm!d8D`?YpQ&5q)x` zZsn3E6Y9cDZkb?dG4J!xX>{xQY^<`TLY&j+mRUwsX0FHaO&U9G%*x-BUf{1X{pq4aj80Kz^u3Q<&K5r2mcVXShS4qtoJ z@99psFS6E)!mrRz9-rip6kOel9Y@=-?=gS8-*xlmbv($s?ityGDoYfn*Mx0pD3FOA zRqMM&H{EbGUQ&H+$mAaT1MZEEqs-glT^{sgzPaKcx0mFOgRhw#3}&d@X*j!iF$Bue zD(;|=`&OA_#9o(K%up*WQ9TT083p7tIr-_&oA^RItb!Hk-I(?uTA68>L`I~f>&|3a z()Ea#8-6VgXKT}KoKzeKv;MDdUh6)_EpP2gZk&kbg4Z7M6n~JdR!cRb&Fn}u)ynT2 z7?(5^{d;|-@lUVj@n);$sP^-`e_p{STSFx<`!Xt<^d2)j7AJJ>-Az5>Z!_@gq8Ht) z)*pN{p{^KhHKToFsB2tF+bMej{?rj%8F5tBp3Kt;iu;r3kD-4{%?4R~FY0=5a6P5F zl9QUsk=R`dLgJ4~emncU9yAQ`x6K0Q`TCE?@aHS?2YFkIZ~p@+o>yN)8%`=LfcqP{av*`A&-!NfJD$%nv0y`vkB|G!Ne;gcp-k&p zjPIL4GZs`Dt23t@^922=e0({jnlNrm{c?>@5nqOrPDd+2MLYLc$W>lNXmPc$SYN1# zcVh61H%Da%A@O9nk7wfj_{>A3|6tK|a{oDNLxazU0dQ7}m7?=L1CEJ~@21&sgD}nc zY)JRz)R>A0HwQ;*@J(gKFlW%BX~=PA<81+~>BBzGQd3@_yDwQ>=Lc^F8{S07J*UOV zL#Ka1fZ1MgR;X!a_4>h!vfr^9j2q|6a4%=MMtnxHPOk1tW1MPx=du-Hc+JsENw;6<;ODRDjr3V&1Qo9n~vR>2e>zs51-th^U%NId+2!act8vnN4uL z5I1cO(k+arWFwCd2BGLn#UXYH&PiC6Gp;qMSRQr^sf<8jRw5a&sBmv*rKh3os0G|x zD``=N6m=MgBQ}UF#gs6spP5~wl}#{dKXIT4b%3^m;2P~WlIDWRPfvHl$o;0= z6-u#XGm9VcyZ{}#uDddi)_?D?TGQ7|t4ntZwn`Ik;;y?@z#Bwu{Ib4I5a1~n#NtBB z+S6y7SV}SnLAC24yvqa~Opt8Nm#=Kff*=R%&cGmnyD(H@u;=}E#zDn73)Ac;wc0Q#-!7%G-(s!6%Mee_Mx;1L&0)~`uHb1>d!oxIQ@VqGO85Uy2?vxWE*^PG94K~YS1QJaBb zLZZkcL2J*8Fhoq1sBGj6Ofl-xOGF|L+CNcYDWsoyP!?BVs@BL-EG~nyC5eLo$W#cd zTpn;vFo+fK1HR6ggZKO>1V5XitYi#U%2AhhTW9bK`%Z#5Ah`Vfu zm<9C$IWh(H12{~{fU?%8g~2#uc_N4kKaHj-C6BCe!7d7r1wRMTJyeT{aM5Q!yLc-0 zI$kga`_O(MSy_Ny802_K#?w$h93sy{Ab009>B-Q(eQ7Lm7Q)mO+{Ru$GxkOmO8ao# zzzuL^7&A>gz4{P9MB0(ZL?1O3?FINJAm&uL8XyhU5FG6%sbxttT6&G_Ni+ilpBd^U zWj}$6e=f+&_Q~VnN(C{&_VeHl^mAyw^8_PLH|Y2`@Yrvq-9F3j5jS41RESno+ z>UV?UAH1v9LF%A-WA5kEiam+z>FK%Aqj;oTKBTfiq8n3kxBPj+XJ!{>!zWKtx_RE= zU(L=9-EkG!v%4fX<~uak?3a3eUTS`VfH3n3TXv%yFPV?j6cDar2G^gCXjxl}|6WX? zKolVv5H1n!j&t*TfTmeMW_Pl+I`aV{RD5(VgRf6alsWz-=MzUt{lGi!QU26uyygO85?ZJ zaY@&o_-O4s_V*kz9B|vP_X4@iTh#B_9vOhISoowQD3qD|y~=>=iNp2ASK6@@uwE8y zgS64;*1}0$5qYcP+m$*mGU$5$KL0#S>#t>R2RB4p10&pInPTt=(%*q>lB~+iR9P;U zgS82FovhIGyixl+!oa=Zb@YVr@0E5<;CvvVuX{?uU+Fc>|Kt&j936v|4Sr@Yz`pw^ zehL>`oTyOYG#XWvK1dZ?K$C!-&S8Sh7r3^6b_@9RiD})VROjqIzMX*%27A+FV|s!J zx=-{GJh_;6!_a{qRfeP9bL=3YGs3LRgfHttY=C)hhG)P!P2}gBb`n_!eqY$beTG^f zHQfNHS*beccoebNTPq>62&Jbcl?v3(Q zidBL+ae6T))|=;u4^l0M&h?gq-O>?-o9ghJ+$iyH#-FFc1|hdT)7(sdwjZl)14P`~ z?Z&V54OOx3JMZ2x#1&HL|CnB4aA{Rn2J;ZZjFu@KQq39HPPJ}5s_nisBd%`L9d=xd z4be`fgIjx|2!zDh*N$qkQ+qf=Iq%!;nHyaBtqk6%=j@f+pA<2d z6-chq9BuS-v$ZXpxihl~+ppvajCy?($&%6*HES0e=Ro(QX2`ZBgG1l)W)!O~cPtUE zTmaLQ-Id(dy8nzYbK_S=<_^v|>v71ZJ?BNaQg*`yj-Mhi7?)x;&$`bzQi`Y98U4TO zT|-{wZQz&Q?R@DS#(&bguiH(^GFIOh5xXF6@Ppt-ZSC0}vGEm0@@90`j2J}YhMGq- z*DRahht9rk6YxFsv*q3ClhkZ_GTX5f1lpg;j67B~WGPq=M#z{IE-%&Q8<(tq8-j~EX*PsOl0WIN<;Ao|!GiGRGJg+f(noD={RnEVD-K2t ztc!N8%$3(g5LE2t@h^yK-ldE7E3{Htka*Ez~I;5MLTlS{yiypL3ikmLi(DrYpX=a;q( z*kBhIDg0bnef@eMlt$Nrz`mzG9LzEGn_=zG|W zAvLc*PgRw}9f`jv9iPSsuK5xyFQS7bxM8fMOcg8yGZ_8k5A8D(P}(StF{lX2P85bJ ziCDM9KJPS#F7itZwMf(|VphoP;6q0`UY5jkGs9g;XTsO@qT|!?!u@f>ak_0r5CYff zO0REDS#`uTC3NbXX#`j&QmdJ=^OHh}0>@&|v>ZP1=9y7nSZM7*8ntV_auQLWC}-=y zU_jrbAwqdR$s(W~&V18fNmw{z@BKryC10ca*NN&`h-%eAtuiqsJZPe^i{_kb6$P|~ z)5_f7G#T!%Hl{h#!ePHH|CDqU%$-caqLzVR1t54L+PGEt!rF`VK~>by=#s`Ln41q; zM_YDNcABf-(zXwW+?k+mdY?rDW+^$8Uj(Kx~%L!1H?KJgymi&ludI8qJgDML%L}_d-&M- zKCEzj2s3mx_ctPYT?o{ztBLm=fMZjjdv%y^^rqV4wCgafu8X`r;^+>i0Nm!aZkY`( zK{Is#u>+EZuE#76Mx;|ia5*O-|QR1r>6D4-cdm{=oXe~C1P`d1-AO)*nH_y9#J8Z3`+B#k%!}Id2alpX4=_4Le zx_Z8GObD&c(Yy<5hpPBHp8A70M~;oWq7-RgT#4}Y{OOO28$9(UP^0;X56>ruV*|c@ zF-y~te#J|L_(f1VyUki%ybNd{2Q_k)mDQ!%zpXp@?5246|9ZL3s3x|yJ0UdbN|lZj zLAn71=?X#sX%~?yO+u9-ND+~Mbfg98O{ECZrAiGTAkrlCjtbJd6sceM)ECXwyY8=h zSZA$dF?-Ks=FB;no&D_U#RKL-x}7wb%!?7qE1NoLdak9UqFdqiZCPSx316EQB?Udd z^lp5DQ9H+GH*MB(6$J}3n$2b5fmeGljoM{XNLfihc>h%253ER7&L>W1oHU7-v>CUzl8;^pe_rgPq4yxo_DmGQrR=%! zt^Mn{`sL5{vUx~f_LVU$D`jXh&@dedE)yD}Z|wK=N90~$`tl^4HycdT$1~CIy_(Mi zGzsLU%)PE@NFya2ATYo(lCR)$KbB)KR6=3lj-Izu)19>AH`fF zY~P&}hj)!l^7P_g8z`JXPj_)>p&vn;f6fQF!n&*YEexL&h+WH{Du^Icy{p!pW2U%b zB4ZY75QnrG1*S%tZ=yTW=^4iK+!Os@s3yx#|>?O z-)_+-Wt50-R!GyFn>+O(#HWggn$Hd{a^9EO-~kbSN+^mS$0O!K@fW}P`v3q(;F9!0K9YAECO^xrGSq zr4eO^@MpcSP-MsS+FC%*yIR_1x+f5*J{C1v8YqfLgQdePf*B-u}&MB%ElO`Q=$JwK_f`XMy zA=6ML^S=mFT527phYJ+SdR7I z*!mz=o$a^h0dJoxoYwgJZ4?2?cI!ysO((*(f9y(-Xu-P z*E6rKwyY3$ief`7K&{?>9nDT^_yxa5|}Zw*m8A^Thb6A=e3JnJZ&*)3KqEYn`%0{Gz@29 z!ivEx;f?;K#&e%zJnaL%CPNYQah$PxJ(eW>3(_89&@xs}@;KeL;-+Oh9*0}dT_F_d zaHxMy-@x{iQ)8pOGHa!Wv-AC@x9TANg;%$%N!1Bbz_&gBglGqpDrHy8qvr!Oy>*{5G!8uag71)CB?oGiqK zNllD~o*hm%oUbRjkN-h7oryQ9ldS@GuN&~1J@xFhTr%a5ph!Q@z`{)yPZH6G!~3r? z&i7Y=0j#a$K{_5!zhZ+&MW|FWdv-=LNK<(z|QQ^G=ve2mn&J(~>5u&N$1m+&xEvkB~y zb*iqj;=cCNy!SbF&tHg6exg)vY7|^^nrmC!ol9^v>1u_SgY9DLrk%?7`7)#Ji0B9> zkbv8VHg4_NpO>BaRowgSXs2Zhy8nII`EIyu0g3(_!{wir9nd1$jJXIJPbQQ4m&*=F z?z?p}Tw3{x2}QHl%nhQ3K&*gSaG=3^6+UNK>r>Va1WDFbfwfSZtNO|wzBV?ca^oz# zzR#f!S*`xeCENFDzxa=S$(I^&KTMjTj}uP+;GWYwY@nq+2qFPNp63(R)-i3eHw|<9 zg$~m8-SqBd<2sdY_FVfJOwNT;s@V^gU6S9dg(zxLCwBl3Uf6vIemd>mCQFu-H6Mx8 zAN6tdzJ7X$yMLjv@KbtjDZdQIJ`%WCWVop-U%S4!>-o0B;v$TPC_>;U%?n>{(w_cmzPUj{o&77f2FMVjUw8Hc@^FNe)Ye*F|UHF|BV~-Pgfs2h<0iY zg6tH`(Dw0v^%#bQ{O;?F7Pq9(pzyDAvJevVsie}w*E^-;e95GkE+Q)=!^h7w!_Uu> zMdzy`E2p*(GZhupbGDCQ3Lb3PHwr4JM-A5jWl9PrX3I0hb}BA2-CIp z@`gQXlc{C_hxkmgIh35fORh7-*{z`GCu|sG?S><9rbI~(RRKzL-Lh)WKeq|s5eXD` zZOS!fYqeb2neBpnt$-f*G{PZq6r*Q|d{5nCi^@^%Oa^Z~naou4O;nc!zO*jl!{ZGT zxMJ0ur#Hy^-WEXO`-850a66?6+}T$dJ#&EFp3lPY@&QALwAVwv$CndS?Gt$@_-Jzz z_lzdL;%0vC@dC$S@hVj)!;pt)b)@$;^;;8YIO`=+(=7?$LG+r_C1f5EExYRG2na`*)9QCY?V?KOzmwF z?Q|1i%bt2VzE_l+0)mJ=9G}S~)5^3kF3X@QkdV4H0%ue3;B2I)DMahaP@BZl zf~dY|kr|PMse{+nMFP*#tsa?1XT+~BE{=6ZMy_4EzTZ+8%G9ll@2jkO_UO-d-pf4; z$wsvJQH$=B=*@oeTB@N-SHCMDwb-)%u>vCgT>;TCv^0>Xk+g6z3*@pRZ`$31$;w~I z)Ohmro|7v};O=d#+G+MIEdoEP5dM5=%lbO1{X9jc;0*lQKxWuB>`@hVcZspSEQPJy zY1$H);F|eL`x=X@iT?0nO_i%Y)0RX>d$JSk^TUZt8y$e;m-kmmZ=O-n%+=w6Jr?v} zyMy8LVDY+KF1a-0>wNfiQNI}ai%=f-B{om&=h zg8;)uGTB=1utaU>g80-Go#$-?dXWvys!m6 zpxxja@((7MBELw%_xQTmlb8LEL}zLhGc&8}P(~o>|cS(@9d-@+R$F?OuZrJoZ zfa(jPmP5R6nzVLmb~aQcor+kNS0jXsopqo8LJNzk&;Lw5r%a z`qf67eMMSWNQsEvB!sY?Wls#Y138pwu(&JJ-!&klF}v+>nBUE{o9xsUO3=C{I>n5i zzr%-Zrc$F3BUDsaC_omC{!yA{!cVbTQbO+oBcN>J?sn(S(p=UX5uT@Z^tZ!l%)*2& zu%)IZC)aSDbG?DW3v_ISUJe8?o9ERKBUelgDzz@$b9QtrnjRBR?7;o{;P5PB8*8WR zh8HvlPY{4lJxPBA*owXn)63g3e{C>M;kV*G9%Nm*3&39hy&^O(xcRUFE`$fDy2mnN zO4laG$;oLX4WEJlC$?>x1V`2ZuQjb=C!ET2!b=r(=*#htMOE>#>fOxj4y9c!Q~)r_r+8rfxj;wq%T7ebMD?V7pnW&#PBp0Ubj)l_&l3wr$CiHmV|X20#Dkeb!Ew_FU$pM z3%4&O=joSs8WtMY7wCp{m~)9Rn$V0#ef|t$>)@gaDTfJXN}mE*mkwLOwg88V?;}g2 za#zPmfpUxNv*^pk2k~Hxi_TbGmO**z+FXX7U*oTEN5buksfZsj$63L27hv`Hh0S8y z!P^f*(remtBTA#x5t+JxNc<2h(iQ1GzE|ZPwq&-CRl%)nVG?7?6~sP9`ha*8oBl~a z&)gaKCaes<;;iVyYSox}tvu}NglxA!#CO>Eh_%eyb{ zGP)w8xIw^x$e?)(4~f3%`n0;>!mu*j3a_NCOYD-`oD?Yw3k!R%De-Iu@|Us(76t_L z#JBA1qJ+eg8tRV7q2|VGI(LwL8Wc4#&9bF>l2x|~Ch+JbwX5POUs&Vr6Y&Taw?q*m zsO(289J?F*2)*oYRBL9_e@?0*74@Pve8i=T+p$Oj-3DZ%hQI?cN*MwAeRmR;UBTq{ zKP3g9U9F90V4bs9OGV_XIc?Iw|8^f zc^VlRnStOlM-*%$DDJN~hgn*;Tgi>05;cFs)ZGUpgOfFC zR9UeoTgN8HB$uz6b`Tkq2cnYvb8L^Li;GLOeJpOdfHsg(aj7bDH7D- ze=RN2I>6%g?Kdx8kGHQYgN*6CQXTbCc8(SiSa)@+&D5|V%D5ik_4V~yUNXZJ08cp} zI#UV17R9wVH#a053d7Bj$(MH!Sv4=_C2Ab95`u90d`@!8CTL|7jp^RruUj4OQfAfR zq|n4cHot8fYvqD%sTRwk#H_F(ir)LyfI7a9@m~%75FsIF(;T1pUN}8ihQ7rDYehKz zHq15sy>cp+EZGzl03~FXjHh|ySE{%4g^Jw^>y{!U)4&2yk8tKJ%x~p@=oeY{y#zN` zSxS8FN|m1Wf5KCfZIv|P7GT+o~w&Xey-L9!#vAt8ehGq);Bykp`l%InnDS)vxj6JQemK?w`BqxH?e#oueJKfvQIv%+!q(W> zSf0K`!A>niu#1N6AYU)fB`iMAx=91q7E-*B>@*NRBxqJbrygB$G3-+*#G-S*qN>Vc z?Vdcm`^M zlorD-XgT6fN;$Tm0C)iXe-yg^W)b5jr*t9wJlmc4A(lz>gp;Y6y%@S70Ubc@N}Cr?ZQRhbLx8*5KeJ_s z(JNZV4T-Eqs`#2zT(D|U&Y^#83D{^*+|kbII}e8y>#j@uO|Ijyyy8MyK?bbo|$&rkGSl-K!!_| zB$HXPszuUX)I3tG9BXv@e$56m{zU*?uSS{#7_kl`t==(VwaL6z=Nv85%ku;#w)uC_ zrNt=r_nYt!6yEHRHU$mmnIv%_A3(2E=N+)UV%=ac@ggVYRIP|NvxAH;gc3~lvE&Vc zx*7drvi>|0+7BPy(?d%aH_-hzBjLM#aRdDFKh`f$KlF<(8!cCgCg~X%2M6V~_UG*Q zF6=s4{WriFMWHK+*9i@^3`z;9HL0)MEUV;_GobWE$x|CDhH&NK;!qx$W)4 zB-2t3mwi{2PuINr_|f!^v-204RntfS>M?q704mu)9$vwH**9;2Y&~}yaOJ<^k)3r5 zXYj@o38372n&wknx}FIb;lKQdSI2eRzGLyat27J-c##sk99Y0ZdYF)`Sayq$*8L@usEz{2k;J`LK?V>i;G>?6%!K^ zJxkedywgTjzOXrP!y$UCBYlO@^f4>2d|1e2Z)TQO;7wze@dN}JS!CQhltvH4rvw$< z@iWiJ%qZYhOp7gaS|B7bP30-}B^*YefR~?t<{-wZe8i84h}bpNWt$s7f1KB4W!g(k z`i6#{Y*r*XT|F21i~NB2p*G|SA`@NDdZ`1p5tMiN(k1FBHZj(@8P<=8GkxXl1p zX$rGyTnQ|xx33oO*W8kRACkz{nn%_kjyyeC-Xiqs6(xXdmkJiV72!T9pN_QP zUa1$wkR#*u#LzmdC0S5UPtW$#9^ZRPk4;GxQTj*?W3>;=aG~o)uG^l-w^U8Z?%vC_ zsxLt0m6nM^edsb{Z4L6SHQP^K7lv2>Af6tb7xDA73_@Fv(7NFt!tsx{{r`FV_yzDw zRKB|Muh8QSevbJ*e*djGqVMhFnACql9EX0Nv}iQq|K*gQA-{_NKZblezRK@AL8l*n z3k3fedYm17yy=hQJI<{=X_4ri{}khj3B(MYJ_df6j-1Q;9mEkpAm$6u&0=S`#(tP3F80& literal 0 HcmV?d00001 diff --git a/crx/0.1.2_0.pem b/crx/0.1.2_0.pem new file mode 100644 index 0000000..6b412b5 --- /dev/null +++ b/crx/0.1.2_0.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4DYEiDPfw094p +axusu7+kP9J9waL3+794PORnMoBnoKEBuEAfeWLZPtX338nq3dmyiVvNsNKFimcH +vVFye5uHdFOfXZ7f6oIBzeY0616dhcASjV7nj0HkuhDhZQGvBWegQrFJrQQDG99T +kXv3mH8e4W6qvwpyRedXqQJC3gE0LOKvUGlWABQwwq9NF5Uf6vJyXYMv7uBMwpWc +liAtJ6v9742IIGjmZhhaQELliOUucbaeilzxJ29XyVXGhEXNERAXbswSGectHvoz +HsBo4YVzKaR2b8wRXGT1W7am1MwFmOzZcX8tQAXTnoThsAL5tLHi+HJ5QRNbSf6h +C44x8bcdAgMBAAECggEAW+G5/pK00FAkj06+MRxFTqzh2w/o2J2f91mGuJH4kkMZ +Pa+Kq2vA0i1RSf45YfvAqyVxZB0K68mtJ6r2Vw2oFhYXjO6C2svKfTYZ339E66SS +v3A92aGlxpawyKTRE1vCYLoKoXozD45BjgmJ9o/1nifyRGE8yNFm7VcdHt6PgUix +914dJWeSwF94tnRqPJwfOXJkpTXdiWQunGWBOH2nK6y/r2xlLiR4EXDA/4LwMegh +5XHWA4YOG0jQc5a/U5w+899/JKvduo5ZU738jKrtcqD8b2G76R+VTxzbv11ROm6E +AMo1nTHRtbPAKDbSSPWgrzjxQPVGbJPJ+BnzF2V3rQKBgQDnC8OxPuhFvEdjmijW +1lPWkB4NBJ9uBtWEMhHe5PTeHs0sfm9AZvM8npObMNcOvmQH3bGX2aY9XoEHZbjK +ixM5miVazdEt0y7UonzcXqjpOvjiqlaAcMP+2Y6ejqi1JD3sflyi/GmLNCtlbRsZ +Fx7sgPNk+LueGvwK35TWIsL7hwKBgQDL7mpjYk5V3osb1AGqcaJYsVa9Qm2izsAl +g13sxollDLazaitwAt3r+FMtLVgJPptTlV37QF1WbSCfGCYjjFRP0WQN1lTlZqUN +4QNKQ6SI/Wp4qjl127T2n/1toc7Mhjs00V+RJiFYpN5cdvXniBXjJC0oh30tL+L8 +Cvws2QYJOwKBgQDJEqD1QSUNg4SxdvkxtwbxhSzR8YL6UzJAwP5yd9lu8Wln3oTd +jHsE95DID6Ipr6IIgnRLDdyyLeumz20ZwB00FSWLN/FiqxZncR2u/yaLC4qMYOe1 +Ee5QfW+0J71FH8xQY8wk//yua/GUbHaXyFpeQv8PkbReLWfJ4rh5/3inQwKBgQCl +7M9dG6BXF6Ihu0a7soeAGJJVnRXtUMFgBFnIi+VAda61nh3Hnl2IYFz0th8aLnlc +8XwtMLqA1nujVpe5drUm2FzLMWeT2wdSmpD9vLnDyET39rCX53J+87/UksHbASBt +IinaxKZ/JG3T1+rOPphoXofroQnFWWAa6KkzqETT/wKBgDv2KDnZqYMSNy4xtz96 +IdOpYioocSvRS5kUUwokAIU9CYIo5+iyaJYok25u6OaRNOr1vqzqeG5j8Rdc/kQc +70df/gZ2Gejn+3BYJtwtgeB25KfCjd+jhTHOOgLbnK0tX3h8X5wkpA0628inwMhg +Q9GxE6HDisGIr0S5PWnZFh34 +-----END PRIVATE KEY----- diff --git a/sql/remake_database.sh b/sql/remake_database.sh new file mode 100644 index 0000000..180663b --- /dev/null +++ b/sql/remake_database.sh @@ -0,0 +1,10 @@ +# /bin/bash +USER=root +HOST=127.0.0.1 +PORT=4000 + +# mysql -h $HOST -u $USER -P $PORT -c "drop database intimate_source"; +# mysql -h $HOST -u $USER -P $PORT -c "drop database intimate_extractor"; + +mysql -h $HOST -u $USER -P $PORT < ./intimate_extractor.sql; +mysql -h $HOST -u $USER -P $PORT < ./intimate_source.sql; diff --git a/store.go b/store.go index 2c07234..45f7f06 100644 --- a/store.go +++ b/store.go @@ -87,7 +87,8 @@ func (store *StoreSource) Insert(isource IGet) { // Deduplicate 去重 func (store *StoreSource) Deduplicate(target Target, field string) { - _, err := store.db.Exec(`DELETE FROM ` + store.table + ` WHERE uid NOT IN (SELECT MAX(s.uid) FROM (SELECT uid, ` + field + ` FROM ` + store.table + `force index(target_type_idx) WHERE target_type = "` + string(target) + `" ) s GROUP BY s.` + string(target) + `) ;`) + sql := `DELETE FROM ` + store.table + ` WHERE uid NOT IN (SELECT MAX(s.uid) FROM (SELECT uid, ` + field + ` FROM ` + store.table + ` force index(target_type_idx) WHERE target_type = "` + string(target) + `" ) s GROUP BY s.` + string(field) + `) ;` + _, err := store.db.Exec(sql) if err != nil { panic(err) } diff --git a/tasks/twitch/twitch_task1/task_twitch.go b/tasks/twitch/twitch_task1/task_twitch.go index 4f0aa50..cdff148 100644 --- a/tasks/twitch/twitch_task1/task_twitch.go +++ b/tasks/twitch/twitch_task1/task_twitch.go @@ -50,7 +50,7 @@ func (cl *ChannelLink) Execute() { for i := 0; i <= 200; i++ { wd.KeyDown(selenium.EndKey) - time.Sleep(time.Second * 3) + time.Sleep(time.Second * 2) } elements, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go index eb3780a..178f0b8 100644 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ b/tasks/twitch/twitch_task2/task_twitch.go @@ -5,7 +5,11 @@ import ( "encoding/json" "intimate" "log" + "os" + "os/signal" "regexp" + "sync/atomic" + "syscall" "time" "github.com/tebeka/selenium" @@ -27,88 +31,112 @@ type UserList struct { func (cl *UserList) Execute() { // DELETE FROM source_twitch WHERE uid NOT IN (SELECT MAX(s.uid) FROM (SELECT uid, source FROM source_twitch ) s GROUP BY s.source) ; //article//a[@data-a-target='preview-card-title-link'] - var err error + wd := intimate.GetChromeDriver(3030) - sourceChannel, err := sstore.Pop(intimate.TTwitchChannel) - if err != nil { - panic(err) - } + var loop int32 = 1 - weburl := sourceChannel.Source.String + "?sort=VIEWER_COUNT" - err = wd.Get(weburl) - if err != nil { - panic(err) - } + go func() { + signalchan := make(chan os.Signal) + signal.Notify(signalchan, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP) + log.Println("accept stop command:", <-signalchan) + atomic.StoreInt32(&loop, 0) + }() - wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { - _, err := wd.FindElement(selenium.ByXPATH, "(//div/p[@class=''])[last()]") - if err != nil { - return false, err - } - return true, nil - }, time.Second*10) + for atomic.LoadInt32(&loop) > 0 { - btn, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") - if err != nil { - panic(err) - } - btn.Click() - - var elements []selenium.WebElement - var liveurls = 0 - var delayerror = 3 - for i := 0; i < 2; i++ { - elements, err = wd.FindElements(selenium.ByXPATH, "(//div/p[@class=''])[last()]") + var err error + sourceChannel, err := sstore.Pop(intimate.TTwitchChannel) if err != nil { panic(err) } - wd.KeyDown(selenium.EndKey) - time.Sleep(time.Second * 2) - if len(elements) == liveurls { - delayerror-- - if delayerror <= 0 { + + weburl := sourceChannel.Source.String + "?sort=VIEWER_COUNT" + err = wd.Get(weburl) + if err != nil { + panic(err) + } + + wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { + _, err := wd.FindElement(selenium.ByXPATH, "(//div/p[@class=''])[last()]") + if err != nil { + return false, err + } + return true, nil + }, time.Second*10) + + btn, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") + if err != nil { + log.Println(err) + continue + } + btn.Click() + + var elements []selenium.WebElement + var liveurls = 0 + var delayerror = 3 + for i := 0; i < 200 && atomic.LoadInt32(&loop) > 0; i++ { + elements, err = wd.FindElements(selenium.ByXPATH, "(//div/p[@class=''])[last()]") + if err != nil { + log.Println(err) break } - } else { - delayerror = 3 + wd.KeyDown(selenium.EndKey) + wd.KeyUp(selenium.EndKey) + time.Sleep(time.Second * 2) + if len(elements) == liveurls { + if liveurls == 0 { + delayerror -= 2 + } else { + delayerror-- + } + + if delayerror <= 0 { + break + } + } else { + delayerror = 3 + } + liveurls = len(elements) } - } - elements, err = wd.FindElements(selenium.ByXPATH, "//article//a[@data-a-target='preview-card-title-link' and @href]") - if err != nil { - panic(err) - } - - for _, e := range elements { - - attr, err := e.GetAttribute("href") + elements, err = wd.FindElements(selenium.ByXPATH, "//article//a[@data-a-target='preview-card-title-link' and @href]") if err != nil { log.Println(err) continue } - streamer := &intimate.Streamer{} - matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(attr) - if len(matches) == 2 { - streamer.UserId = matches[1] - } else { - log.Println(attr) - continue + for _, e := range elements { + + attr, err := e.GetAttribute("href") + if err != nil { + log.Println(err) + continue + } + streamer := &intimate.Streamer{} + + matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(attr) + if len(matches) == 2 { + streamer.UserId = matches[1] + } else { + log.Println(attr) + continue + } + + streamer.Platform = intimate.Ptwitch + + updateUrl := make(map[string]string) + updateUrl["live"] = attr + streamer.LiveUrl = sql.NullString{String: attr, Valid: true} + data, err := json.Marshal(updateUrl) + if err != nil { + log.Println(err) + continue + } + streamer.UpdateUrl = data + streamer.Operator = 0 + + estore.InsertStreamer(streamer) } - - streamer.Platform = intimate.Ptwitch - - updateUrl := make(map[string]string) - updateUrl["live"] = attr - streamer.LiveUrl = sql.NullString{String: attr, Valid: true} - data, err := json.Marshal(updateUrl) - if err != nil { - log.Println(err) - continue - } - streamer.UpdateUrl = data - streamer.Operator = 0 - - estore.InsertStreamer(streamer) + log.Println("streamer insert", len(elements)) } } diff --git a/utils.go b/utils.go index 64f9efe..774de66 100644 --- a/utils.go +++ b/utils.go @@ -51,10 +51,11 @@ func ParseDuration(dt string) (time.Duration, error) { func GetChromeDriver(port int) selenium.WebDriver { caps := selenium.Capabilities{"browserName": "chrome"} chromecaps := chrome.Capabilities{} - err := chromecaps.AddExtension("/home/eson/test/ssh-key/0.1.2_0.crx") + err := chromecaps.AddExtension("../../../crx/0.1.2_0.crx") if err != nil { panic(err) } + chromecaps.Args = append(chromecaps.Args, "--proxy-pac-url=http://127.0.0.1:1081/pac") chromecaps.Args = append(chromecaps.Args, "--disk-cache-dir=/tmp/chromedriver-cache") chromecaps.ExcludeSwitches = append(chromecaps.ExcludeSwitches, "enable-automation") caps.AddChrome(chromecaps) @@ -63,8 +64,12 @@ func GetChromeDriver(port int) selenium.WebDriver { panic(err) } wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port)) + if err != nil { + panic(err) + } runtime.SetFinalizer(wd, func(obj interface{}) { - if err := wd.Close(); err != nil { + log.Println(obj) + if err := obj.(selenium.WebDriver).Close(); err != nil { log.Println(err) } }) From 1d2f2d14c52edeea78896bd4e32c262189675535 Mon Sep 17 00:00:00 2001 From: eson Date: Mon, 27 Jul 2020 19:30:54 +0800 Subject: [PATCH 2/4] =?UTF-8?q?1.=20=E6=B7=BB=E5=8A=A0=E4=BA=86block=20twi?= =?UTF-8?q?tch=20=E8=A7=86=E9=A2=91=E6=B5=81=E7=9A=84=E6=8F=92=E4=BB=B6.?= =?UTF-8?q?=202.=20=E6=B5=81=E9=87=8F=E5=87=8F=E5=B0=9199%=203.=20cpu?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=8E=87=E9=99=8D=E4=BD=8E50%=204.=20?= =?UTF-8?q?=E9=80=9F=E5=BA=A6=E6=8F=90=E9=AB=98=E4=BA=86400%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + crx/0.1.2_0.crx | Bin 26871 -> 0 bytes crx/0.1.2_0.pem | 28 ----- crx/myblock.crx | Bin 0 -> 75903 bytes crx/myblock.pem | 28 +++++ extractor/openrec_extractor/main.go | 5 - .../openrec_extractor/openrec_extractor.go | 29 +---- extractor/twitch_extractor/.gitignore | 4 + extractor/twitch_extractor/twitch_test.go | 13 ++ go.mod | 1 + tasks/openrec/openrec_task1/task_openrec.go | 5 +- tasks/openrec/openrec_task2/task_openrec.go | 14 +-- tasks/twitch/twitch_task1/.gitignore | 2 + tasks/twitch/twitch_task1/task_twitch.go | 1 + tasks/twitch/twitch_task2/.gitignore | 2 + tasks/twitch/twitch_task2/task_twitch.go | 10 +- tasks/twitch/twitch_task3/task_twitch_test.go | 114 ++++++++++++++++++ utils.go | 4 +- 18 files changed, 186 insertions(+), 75 deletions(-) delete mode 100644 crx/0.1.2_0.crx delete mode 100644 crx/0.1.2_0.pem create mode 100644 crx/myblock.crx create mode 100644 crx/myblock.pem create mode 100644 extractor/twitch_extractor/.gitignore create mode 100644 extractor/twitch_extractor/twitch_test.go create mode 100644 tasks/twitch/twitch_task1/.gitignore create mode 100644 tasks/twitch/twitch_task2/.gitignore create mode 100644 tasks/twitch/twitch_task3/task_twitch_test.go diff --git a/.gitignore b/.gitignore index 331f9bc..1796cca 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ screenlog.* intimate *.gz debug.test +myblock diff --git a/crx/0.1.2_0.crx b/crx/0.1.2_0.crx deleted file mode 100644 index 54ac5ce1ccac8a5f21ed789eacd2a182647ecdf0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26871 zcma&N18}8Xvo^eA+nLz5?TKyMn%K4`wr$%J+fF9Q#J2h8dEWD#I`8wH_p5)^?!Bt+ z>U-7RtGlo6)!j?jfr$kK004*r0|3aCpwPv@3;{qy3~=C3R3YLak8nUhKwton03Zaw z*K=s#03aYhE1W+O?Bmt^CZ*N4%8s5w{yFbo`H!zXZajNtOnzp$c|ffK`0j?Qe2b4; zqbI*t>%+AsYv+O^%pkfH96U2Zos@EPvbRnGfF=)EPIa?_dy%7c4}S{owIlv90jdEr z%N44Vr~(D~wxty3`Izd9_s6!p2iigOP^}DDXcLHqW~WBpLKT3@&{rdak%WJ8e=cKUs?gM`Rt%SwZPAfbvsWE?t&;<5+8Xm zF^tzOxWFJl03c*P;QAHADwm^o+1e#NagLvIV4&tw9nqPfNJ|w>N*{Be-t!A+=@ci;>mLn+JZ2RE4p;@0?@bbJY>i`YYmSGDRSy3quB9Lge|ZSO z?feV*H*34jnj}gyb5<{TT)GPqzn7~URpwIJbQVg!vQEE>Zt8t?sSFKN)KMe@sfcVs z(}boRKb}Re!?68FMPI8=z{{zofHF=a?Rvgc)19lmW06a~j~3e!XMXW6qL8!z`rW%rlQ%xczVFJFG*z7!y5~zt z0<$=nDJt#_p;{Z(rwHxcHOk4cJ{ZP5gBCPvlufGniv$(^hupz@{E|4kx)9J}BX)&m zL4C3A@d2dL{4@jWJFpV_6od0F@O){G0rowtl7Oz=)GL}u&?-=)&;fV^+UV`mG?~;u zjI$J#f2qA;NBnJ*6K2R%L_cKFZ2h$vZHn?&L))QIS&6;R^Z4et##RT=}?A3+UcV3P)D3DKc3Gn0&y zs3csZRCzEe?#8fift(v+T7%<|1$^1Q{zOQax)>9s*}N+tZ91%~RvJa-8+xqklql8~ z*{Ouz19ciK?{8H56Qepl=IIEyw|P1r$4NVzAWq_p!sC`2e3(t0`hg%0%Nr_M+rQ3$ z8EgX~Knm}hms5;Tf}kEn?kQI`mn!-YSQ-WPhC3M>&PPEn&uQsgTN3`DvR=N@1079s z9TeC;7pz92Up`Ft)`B~=qCsH#qcJ`^b>=v0i9Hv=aWOajUe1y3OuJW?5!qVT?eAPZ z?DDTx%Q^Hh&P$r*;BG z2d>Z2MrkvhIlO^P9zvmFZL2|Dna&7#Rhcf~z#djr=tP$M+IXly)ML~w&B&y-B{AsUs^ z(<8&7b8;||3$lat@Z0YM2`*!~UlKv9*b1TY-+Kq$kI#=MaFiK(yyw-0!a94JsY1T#b;xZlS?ku0WKqJ~p{{OLUI3e(GD*BC#byEzRJ>Bgzky~ey1 zN(56cc9+sFJfL=3+1o?M^`?4{>7nJ`!K)=4NEez>F0RNc> z?2E_Pz{%j>m{5XW4#JcIkP=6A%U4D@1n2LJ>5WkM)9KS4@7DWRO*C@41nlk-0(y<33V;)H#&Pd8UF|(K4nMKlaMa6-?yV&;ndfRf9HcXPn;7+uxK(J319RN?ywc|n8P z1V_fh#l+Fs*OM?*xUwi!%CroYKYKTZ3%X3ZqR3fFQ)^(@?+B~&SY?|(%cvYg*;Ho7 z5J78>8APh)afsP1F$$aJDVls86D$365|?BPlno{n>X}^>G`XYa;F!(I;#Y&;Bg~eH zxSkF5>XVaU=65XCY6lMn1mn&Xzk?@jfQ>%^9MQ8xYrKgPo1ZziGf<*qy1Q&rkY=-L}yGQv+;l>}*z?+iTjHi%7l?OjPS`?)$RZ zvYI8TWcFcF`h;fkNIdi2^U?kbbRInLUS3F1P($T}aC~uQa5M?>)jDk-!WKh&;PgAM zSc?Z{Subg;VZh+%Q1o8F9v3cJkP;D8H?JHBp`ZzMDlU++Bk+S)L9gKwb&%>QVZNJn zyI0h9(^@`MBvY_RJ5MTL9K?9v@1%*6qe5JXqu0X*`a(aM`>$CR@>G0RAY(A0l35Ub zs_}jY6)$0r5~I_kjMx~ol_WZaG@3e_C(9DMgN1b^t+Y-`IWW5nyF;1vD6O(iNfjjL z6r0*@L>i*Uw#{;qdctG)2bZVl8-%a*IfWD3wa=2<9%=#+n& zg}vwPaXY+?>rj@!@Skh!gPqq=@z_G{wgk$l-=ZsJU=9|2(wOyNt0~4!{P_wdMUa)E zhm8~A7*Gr8JUZKTYSd2AHX+Pw`}S#H%nQBWyZ_YF>AC3NLK9^CN_)MYd5>>WNz?oR zCS$&;pp;)OFr8HqvlUlfv=;rMW_*ZcURg4ZT6z*eB7nvZJUtoBKZQD+MkpI@unTS{ zocVK8P{HS^RM&A{YQeJ_5BN4eqg>4VrX63dUMcZ4OVS)+f^BjWKgR3MUNLDDMW$;s z2R>K<@^rkAfTkrj{GeEh;*ObQGUwOtoA2(qok{T4etb4;$sgLc&DCwOSSW;q~~blU}5j{f7##{+keCPU*`HZR9k$#M)wHZBk_vioAH`6BEu`WxN<1p|f#MpkAHcFwlObmmSr)(r|y*RJs4u=Xk= z6r+=MyZiP2bI{OiSY_dqE^KXOq~Xw`SmC0BWu(oLMWhz(=#nmMFZvR-^@VSVk_<2- zbh30~G!zOHbdt>~bMy0ZQ`1u8(#zvi;KzO=21;p}3W+%x5oHr%_?B!lTwxXe@KjNH zGo)HyZp;H70QhUm{>RV!7ifJU(WIJ`-8u(iH^hjqzPotoLR{8>6)J1zVE($W-@}~E zqarF8?JS#C+CqF{G{L>^Wt2FtO^ZK5$2ZV8k*UZnFXn#hRzjZX(I}pa;zP4TvnwRK zpgKirb!}9tA5UXMH|9aqQADF-M@?Zed6_|nimk5NqrtT?qDfS1LQ>SR6VHm7hUIhb zim8?Lhfg@dMO+vW-PWt1SPb9J{1c;5h+9$4;`-3T`nG`ba0b|c`LZYn=+>T@$H5Gy zQMX1&UDpP*80Fx?uxj0W#9kCM|L{?jRqkp$T)%5A@sVeqbLQ2sF+)$IC;Ghi@$MO_ zDvvqMfSF*(Ahgb(Y(_@199X=lYLX{1R4SkmPH8$%q7Brej}aF7hFj0Zv-P2;Rj5Gz zntvVS0DS=JBWYNTk}sM}H)|x78Br})wnGX*K+K`TInB&RA~6Oz8;f2M*HItI2&?$n z1Ja-EpCD9ZNSGu(Iyi_F2OmG*9jc7s4&4Th(8SD;XdxyiX8SfR8haXUL36?-?@EI()`l~w7;ALsovI>1@VApO zakYfUwFT}glZ&oKzKeJyBxR*3&>;q$p>VKdC5clD4s~o)5(oK&0~S ziq{zHbTO$4uo4jRhO2>W!`{(K?IQGm7IYpLFP`)pO7M<9KGYeZkx|vA{kg1zz*ovj z@7ua$S)oOobp*ypFp`cw23f9kC?j+YfzH4egjHB_9)+XHpQ@`53c?*)@`HfjhK@=r ztt5L&VFs^Amwcux{6khf@&jSok@$mh8=8dxJ)T0$dQusR)sbXHorbvyS ze_Ovj)sbi*+EmdP?zt?nFBZl7@Jef^J;!;|{Bmk*(JVuwg zf)RkoJT2eCZFqP(4NM0a@=y1|`>r0*il@P+RKy?BJ!7ByYNeihtw;2mo&(+I8raM} zp4wrZ4&gsyhucLYduMQRs+Gjc{UtVSG8UZ}h6KZ<(O4eXHBy*b%k6<)pFsbP-xfJ< zoEm?D(H9Woeu2^70Q(R8wy?D{G5YIt8>}khxXy;i`@IMF7a=fhnq-Zsid_0=9&_}3 z8F$x6IxJ{4Nz`*5aIST9{^zES-%hABH-r|!6`sqZL0x1Qi#6%u?ogsiTs? z3K$9!cMRq_ao;|-Hdi+Co2r)50b)kEJ+|-o4z)TpJK{LYyOI_JSn3oR_(w%=J7t4> zp?=@xmcFZr0in9SwGKAfNUUrc-N=S}Fk_b~FgZGxPCWv?z1NCho9SWMv)9zqD$Y+$ zUHzql-7KedKbwLsm;HNq-a{S5oaDgu3~YO@J-gJON9?;;u)%xd?q~N{-=$&CGYmq{3Rp9%v_?tM%c5A<@M^Pa77bgI1WXGX?6^O#RfaE zvu2v*RH1!?-|Y36a{pY0@+KR9e~LYQtLw-F%S0X`kLM)i7KphIkJ2Q0UYb3q6a>>pOE#?m*=0R3ZV zlQyb3sgq)!tBu*7;(K=m&dj~XoTw(BLT}FLs3&qiN^xar{lp|=Pa|1-+u7g_9A}EG4R6~$qBQJuZqU{WG36o%vRyL%02b=EWgmJU4Y8=qNENcG zA{bc=T$NrULPuPzu_Ukth(J>qH$y#Ya*1fWd#4hLz5965=uK8V#wCAxMH`6NE=fTk z%f=hVUpacKSi&)a9-&ifT(H_X(rZ?cKAMLGf;RxGycCI&lc(COjg3(pgoX-Zj;+G( ziOVCp`7MpG%0vr#+yI#S^63wC40ZBPf3wiuYYvN)X{w>JW)2noB`CWHI`py_(5VzV^S#&yseOaoWhdO3&!%j7)x0tPSpLsG#Z#9gK>01+{rw+MV zL4ENqc&F&HdfcFwB)WyI3qkYNN8Hl*LESY$YxNWN4mLN-{)?9)y4GcY9x|7+{p$SB z_&sD>#tQq}8LRH!tX;viy7Na(JgNFb44_e~138X!f84{jOi#RGk4?NXjtPY~2u|1c z{IKp;Pv1~Vcug~5XS~ZhCv|7E^r!Z1Q!MuBZ_l3BZ0lTkMtQZDN7?qYJPW%{uF8v2 z*^cZ`;~|7V@*1@Ve(-EC^O>Y!>O~h6w`Xe9`8O&O1of@q*FD><{KixP zXSlaY$hW;waL{<7X_cG8>gvlT3=t9j!7V2Cf3fdmjQ;5R0=%v-Li%@h77jXlTQi_8P@&gwdD-u9 z(AZyxL;#$GxQOD{%{XYQWE-003x^govQBx&L{Zjk%Tz=J4lqmxN`5kc?e} zVMWXi8CTOWO_^e%3L@Ep0g9G^lM*UB=8paegy6uK6M-sHNj@6*VwKN`lqiPC57}m- zb|)*LUkFrSvyyrA7T>pQ*FEw0Q!@rM5=B(En>V*l~rU04eJtBJe$E0Awj)FSU_`UM?6eF22St!mbSKfR4XSZ=$xIL z+^DFiE&$t9s#tz}m`-?rF!QauyE_KI#|YLVfZx>A6uLzG6mTh>Y8==_Krny=5Nq-* zVI6aejWnsDunhp1b}!-i!ZL2=mJ53x94?=#sKoh?hJl&9VAXbgv+1QrC{)C6p`+Ol z?o}vknC`Wpmb`7|>L}IH^L?DzGY%YhyII_l0A$Rf!GgbwIK_s6_y4(S@qj{7kciLy z-QN0iLfp_G2WaIp(?z^prja;gJ*bJIfCdHD3P0lT8&1Hql&smqt3DLrS|KQPiAihCS2P7(F8b3i0qV?P>!^CIC&pc$ma|4{^l@1R-YN0l0(h z&A=xbOoKiVuyR%ODVYr)Qjys(03aR}4cFM&t{kdN=wZ!iajY6bs{s9*a0YyS71i<= zGvEt$Vl5|(`h-6xC*K4cWAQe*=jI%;6f~$wNu(hUL`l~`Oy3WjIZ2P*3+h!RM`Ta< zl@jseXvh1Fe0(#IetqqoAdv^YUmV;dxV-fFzR|+DPhvQq3_@0b`PEIe&VBHnVVyb^ zaySn7HiUg$?@heP*RgD?x*`Mk>Q%4UE#u4{mRwWIj*SQ>T8w_Yegk|P((l>J%7!0= z%Te|)&k=7LVq_C0dVnYW>NV%x{q-S2=q68IJW{NH+*qSKI8E+PPL=~4h0d2r9#)j= z@@OgDVgugATu^3O_O9QO?_Txf8k_l2t*zG6<-Sv(rsH5^a}h|)*%FO;m!twqI)OXb z!`ZFg%zf9r1b|>T9CQJ)i4UeNY|i0`Bl`Yafr%<;raof<4#SQ>V|}tA!2?SGcPr=K zbf6@UGIBYqb)9dBe(U${;Iiz)yRVUp6+LmZTF$kIuutGtR^B3sSG05w=h+#KYF2A- zB6p!^T^;}wwkLB)Q(M{A-;+=+-vHRl_67Dm(^3aA)|Z=I zO>`+0-ys!1a?``8Zb#Bg3VaQh!j7a#ke`2vahr@KQYsDM_yP}7M~7DFcu#%752?(_V=0G`0tk^+ANUb)4OO#lE~{4cqlqP9d&Y=7#Mx1pEZXj1`ziWVTaNaZcO1?6Gw2v4--SKJ1W^ ze1`GUF2J79PD)96G!_*NHZ@qzJ^B0#Gwnqc@bnLqsk6i>b3(#@fdG(rb(NHup?V*e z?#ctLfUZ2c=t0z>1W4;`Oi4hQF?x3ZkN^r=S{aBdq;`{m^N__fC?|Mzg~T|(ix#ad zQc9Y84q|?F4&r(hx*CvQ*oy|Ob-dI-=f~>7!7f5`V-%vuPkxQc{dEV1^|+ z2vPL}J0L8bxk#Jw^-N>-r#qRS^~R2e)B1$F;GXaM-LW@TdNZK+H*dGdfa$v%PqsEd zCWGCs8`KG1P*fpa060W{94^3LKroy{zUo0ya&V{2ohBPv4d;g$(b!U!^#it#*^ zlk>ZO+Z9GMjnn0FQ?p>r#KdGb^%=z!Z)=_VnpdrXjWVfxg^F1suEUpXJyf>@gA8&Vl zKK*rOztrWukbcLGG~Y@4Hd8FD&gsK%q($0;6DZMl!xtvC-b2AK-+?wt8iIq1dCf@9 zyL2yM6vwszBs^}W=mKT{7MTWW06*MMkxmZ~MqkE-KGM7lx4P!*CiuX5HgR?kOCwG>1pLxY+Ok=c9o&t{pd1cr42?=@yUr%nUVIUkFV zFfBxF`&L07FkF>v=2DJPB&3IccVNFd?Uc?y1?~aJzn0Wm1~$y@ad@1EtRLGdv@>pmjHk(#;dALfnIL0hTaID z^>>rrnI_>-T|h4XOH3IhUACEsG~_iSk`3b=8x|`7U{6K5&k9w!w4Uldnimi-jJ$aB z`VQwW(Az(e0Q8om@3^k!&(TKRP+tw0*#ash5xEkVkPx(swjC&z$!MmEU;^*$01$aw zBvgK->7KL{&{a!{XhoLG7%+8wbDo!$hRV#2D5Q^KUVtF;Ut0tA2nE$d$@BqjFUAimQ3 z_}G?6GZ7_x4}iIG&gr~%1If{FFp-8E&c)$!wi4Xl-ri)}(vh9E9)8pji9uh@<9=g2 zY*RbDJBlHM!@`fQWDk9-R+G)U9$RhU2)J`n)J|8^c~4G~-R(iNXi;1sKqdD0;qKxh z<$K^fFPx{e8aLtwK+(TBc@--K4{}$!=!2V1A)xGE;&32xb4%aK>%0dh@qq%K-hCuQq$*Ln!Gh34 zS1p@Lkv|KXn_W`Y&$~eh@WbDem*Hg*XQQIOv0pT4who_O&CSg@QSQt1aH^sf<&>9K zcXKGB7FB%>xmPFN^y1O6u`%lKW=H$~8m&;D0NPoZoO7UAh5zidE`(t#>c0wgRbTWE zr^U$jx6`TuQvCQ|oEGBOnuvcpE&SV00{{TX=`W|n5j_~+C1oUtI_Ue@Ju3W0@kSs8 zEyztcC`JN~B(mBBO&PCBGtf8XvYv>(ra^i30Yr%8`703|30BjpiA`t^3lH)qyO9yW z07>%Z4f|oHrzz&s1(Kf^AOEW7_Ui|DEjbZ10ny>2<$bG~S;XKDJ`(4Xp_J9dc@>x! zJRrV*qC(LAff~|*h{Ake%@T$CDqY3e;juEI2W9FNlg8l z6SImlFO!Ou4L#`g=;I+$TG#l#4=hv|I9r&=!N;r5Z%xma)^0xFSlJSMKi=GX!bla7 z7dF6Cigb1GP*ijORdL$nMasB|R>h($&$O2P)H_&qlp`JT@oUTg(R^sxf+iU(J$k== zSwD5s7;`O*eiY;I51by3LlF@^ZwtTmI>z+fUA4e;pUX}VoC~+@=HHYY|5?CkLT%TU zUv)T>FZzdonVJ3;un9=|+y5e9g0D3R{uZ#KhsPZN07CPZfYpP~leesJzM>NT$Ia37 z-zwias?rIPEX$CzQH}C{7i0m&>Z1!$K&&fS1J!i z1kWW|S_g~gCL_~|Y}7YUckFI*@{#CAH*hDc4nMrI*moa#c00B{Zh)}ccL|e9q^GBQ z05~8En}-^gDxST33|w5;!V2~QsF8y{)3*;=Ruz^``B6z6Yx}{Bc*kPHY00LZ4y`S!zHLlMeMbD`cYnUkS>qxCl zzdzpYo0{Y{)wRCmlrHM7E?eV8jisffjrNH_Ama|mjHq|%rdO)!=#vuwmnc})DFvLi zzg9L~vSCM?K?nDF%OVV7l`ZpUR;ucm?h0fJ?2QN~jY)>~vA3+Bw^TNL_s;+X5VTI# zEm0XwG)HbBgX-Z`tCoPiB#m5q6*-6q9zkVgXY*NC@m43cdrFOvocndU?T?B2mn4p0 zJWK93)$Rlf8OT%K$Aw9Ugku`vWJwk^dxI+@di9L29s1|mOelcm34f=&7cbcX5bcn( z1NBcHxa+gayFX2&<#1mI5QJf4i;=g1d1_WI9hen;lcQW*6xe|`W-rO}TaE3&>$D~Xd_a-H>1D>pHZBj*c2Iw=Ua2x+&vA4@v%F)5Z z-)c)zqDuPERafUQjT!|Z?{jjhSd=st*v>`(hu}rh0K>CuS?7Oe;Ch)G3=jXLrP_CJ zclPo5&?s7f>D{*y>UO~)j|1}K$32|!6c$dYQrrRvL-SR$V*9>vaA`vCPESrwnl!Aw z`WsnK#OfuUw!3Ot`N~-uqMXXf`ObfwFdfaInO8b6Nu z`>V;p!@eceKP>2O@uRUT(9_a3t*8@dDePg6JPq-*$IFIZfEqkabIa49zb-E?&+~GQ z7-R1{tX_)lf>+bOf!LLE2CDNx{guV|561(T98ZjS%3*s?Vg1-Oh@wqp4RLj3rEIjHD(DQ!5KbAmdChJ(Y%Tg7C&;tHNmz zhzZG#v2Ehrm52zxo0gO-h1RYVUTMX2x18W{Azz|EIfmdey~5e zBRJ%6nt}rI6u1+UxbvLaXy6aKe>h#OreN-lr_gx5mU2G(26ueB%0Y^Bg-Yaa)4{o8 zd^43f*jw+>4JDtMjJ`c(VS_zZ+I523i0g}FsdN9yitdK#m*0QJxpZ$NKv!?H{y?XTXB(5@$9BA?hJ=T2hSaD96EtP!dXYGk$6|k5krK=b zY~gT#w)e5&)BYyuM~|kfez}bGj!3$}zD>BZbBtA0zNM~?U^G!xS?L5dj{TnCswmo* zE=zL9^gVzG9i;4RaZ4pd^fmiiPqJ6c5UW9w51;W?oY$>^Yaw&dgEZT%1=gxoj(VX7ZCfDxZHuR(O3AoN35%zxvIUX zq(erljwc`aUXqUz<=tkDzUi7Fq4YZ7?oIO?pLgKOXOP-WzQ?DiyCpJunrYiAhRfgMwM?Z1 z9*`!66FzP~-&aO|*OaQ%chU@o0fxD97MIpMWtJWJ#p({b$W|_kmI?q%7R;XwzkXD^ zR4v;H-7mfP$)1b^G;p^lTd+5rD%IV~`x(HnNrIEX_G=JYWW2S~b;o+RiyMED8gTBsV-|euB z!H1YQIOhsMe-~ICo zX@v2G!kqy-xS3eAQGpDRtPDL!Rbr!}csOcaLu05#NF~bmRVpgwczF@4jAP=+5@#ab zd4q_NxALiBVd}yjPP0X9v&5_@2OrMeeX=W(ow#a*4l}|bj=ihc*KN9aHNxUVoC3z? zcXn#}%S0&1mN|nBXon~J4kF=-aqlmkti;sI%lErGw@d!F&X(Jt7f6Sw&E6mw;{JZq z>)(|zdu1>-v?UDrakZu}>3=v>rKEEgCTlXlL^shiq#(3sVpYgMmANYM@NBP)~fg6+NHwv=UZyA7%Q5E5<=75h!t0I&^YC( zsIV)rBdz-gE19_lr}>zdsfw3OQ~Rp3`nv9q!b-9@ruFtV3m_Y-jpr8!Z;!R+vqfh` zTifa;_V^q5)f+4@!nRRX-sR*(63I;MDU$Or<(m86B$k4@lQNQpz}gn3>D|-uAi}Mt z=8@mXErv)@>}`XxMM$D&bY7F~5ju#%RQNX@IeJ*>z&WiVIjNa@kwB8mWG08+HWATJ zm}K>&Fi>-IxV9~&E_+*5q+_s6e%WgD;m7mBOye&xwu201+#aB|trBx@MDvZp{gD#{}WiN#YnezqH>6}(^LP5Gp zm$TWc&a>#2iiKnkHhmclDkU`=<+mLy+-gmN&LP;^Fc;0-TicW}RzVSE3MtNGuc&Bs zlx~y^B8Uk^|LRz?#~hhA^`MLp!|r&iIIZPCsfg=jHc8X)=eWdLdBNc~=H;=E-d7Q}I?cU|!NyRu ziyjV(L(I8fQVx~Za}HW99o;L(K^{{-Jst0T>HG2r2}yR0hq0u{f{xTEpfPo&EIkQ}q4@5T%)*0*0PvHRtx*=Efx1gT@yeP#f^;fH5iH%R=w}hKOgVv*~E$~+Si&fAC6{;h3G*Kyb}#eitQ|T3RIZ7hXqg- zz|z=A`gi?{wHkMN5kQygJc4BJJi38Ijk_cC9_fl=Ta~EM&e=TGV|o#r4A`$3WkHyq zscnX91^`b_6rl(9N;ss_J^fJzxSW=j#$=@N2S>wP)%16>fHw_nI;e?>3E6OAfOj39 zEe+m%YpVGLE3e`YWy4&pO8M-5%T6wDBYJdg04t;NcM-JfiH_fP$0xjju=UD~FUht> z+1U!DhvYT8Bye-v?|)~}JR1)zf|y&#%+lYjaAnAXj^=$e@=XMudBsy(>J69F~U`QTbu{@GQ)ujIAuJj_@d;9kn`KeKS9yuYl{B?QU& za#iv{?9_SLW$1g^z~4J|L(omWi&LW4d#_nUh+OPwGo#$1#?u~(PAw@UCWs0wq*c;L z{BCME)Rk}TNEFX5!o$OJ$A01y<={_v{f1wwVC!o=zIH_Y%Vksm!d8D`?YpQ&5q)x` zZsn3E6Y9cDZkb?dG4J!xX>{xQY^<`TLY&j+mRUwsX0FHaO&U9G%*x-BUf{1X{pq4aj80Kz^u3Q<&K5r2mcVXShS4qtoJ z@99psFS6E)!mrRz9-rip6kOel9Y@=-?=gS8-*xlmbv($s?ityGDoYfn*Mx0pD3FOA zRqMM&H{EbGUQ&H+$mAaT1MZEEqs-glT^{sgzPaKcx0mFOgRhw#3}&d@X*j!iF$Bue zD(;|=`&OA_#9o(K%up*WQ9TT083p7tIr-_&oA^RItb!Hk-I(?uTA68>L`I~f>&|3a z()Ea#8-6VgXKT}KoKzeKv;MDdUh6)_EpP2gZk&kbg4Z7M6n~JdR!cRb&Fn}u)ynT2 z7?(5^{d;|-@lUVj@n);$sP^-`e_p{STSFx<`!Xt<^d2)j7AJJ>-Az5>Z!_@gq8Ht) z)*pN{p{^KhHKToFsB2tF+bMej{?rj%8F5tBp3Kt;iu;r3kD-4{%?4R~FY0=5a6P5F zl9QUsk=R`dLgJ4~emncU9yAQ`x6K0Q`TCE?@aHS?2YFkIZ~p@+o>yN)8%`=LfcqP{av*`A&-!NfJD$%nv0y`vkB|G!Ne;gcp-k&p zjPIL4GZs`Dt23t@^922=e0({jnlNrm{c?>@5nqOrPDd+2MLYLc$W>lNXmPc$SYN1# zcVh61H%Da%A@O9nk7wfj_{>A3|6tK|a{oDNLxazU0dQ7}m7?=L1CEJ~@21&sgD}nc zY)JRz)R>A0HwQ;*@J(gKFlW%BX~=PA<81+~>BBzGQd3@_yDwQ>=Lc^F8{S07J*UOV zL#Ka1fZ1MgR;X!a_4>h!vfr^9j2q|6a4%=MMtnxHPOk1tW1MPx=du-Hc+JsENw;6<;ODRDjr3V&1Qo9n~vR>2e>zs51-th^U%NId+2!act8vnN4uL z5I1cO(k+arWFwCd2BGLn#UXYH&PiC6Gp;qMSRQr^sf<8jRw5a&sBmv*rKh3os0G|x zD``=N6m=MgBQ}UF#gs6spP5~wl}#{dKXIT4b%3^m;2P~WlIDWRPfvHl$o;0= z6-u#XGm9VcyZ{}#uDddi)_?D?TGQ7|t4ntZwn`Ik;;y?@z#Bwu{Ib4I5a1~n#NtBB z+S6y7SV}SnLAC24yvqa~Opt8Nm#=Kff*=R%&cGmnyD(H@u;=}E#zDn73)Ac;wc0Q#-!7%G-(s!6%Mee_Mx;1L&0)~`uHb1>d!oxIQ@VqGO85Uy2?vxWE*^PG94K~YS1QJaBb zLZZkcL2J*8Fhoq1sBGj6Ofl-xOGF|L+CNcYDWsoyP!?BVs@BL-EG~nyC5eLo$W#cd zTpn;vFo+fK1HR6ggZKO>1V5XitYi#U%2AhhTW9bK`%Z#5Ah`Vfu zm<9C$IWh(H12{~{fU?%8g~2#uc_N4kKaHj-C6BCe!7d7r1wRMTJyeT{aM5Q!yLc-0 zI$kga`_O(MSy_Ny802_K#?w$h93sy{Ab009>B-Q(eQ7Lm7Q)mO+{Ru$GxkOmO8ao# zzzuL^7&A>gz4{P9MB0(ZL?1O3?FINJAm&uL8XyhU5FG6%sbxttT6&G_Ni+ilpBd^U zWj}$6e=f+&_Q~VnN(C{&_VeHl^mAyw^8_PLH|Y2`@Yrvq-9F3j5jS41RESno+ z>UV?UAH1v9LF%A-WA5kEiam+z>FK%Aqj;oTKBTfiq8n3kxBPj+XJ!{>!zWKtx_RE= zU(L=9-EkG!v%4fX<~uak?3a3eUTS`VfH3n3TXv%yFPV?j6cDar2G^gCXjxl}|6WX? zKolVv5H1n!j&t*TfTmeMW_Pl+I`aV{RD5(VgRf6alsWz-=MzUt{lGi!QU26uyygO85?ZJ zaY@&o_-O4s_V*kz9B|vP_X4@iTh#B_9vOhISoowQD3qD|y~=>=iNp2ASK6@@uwE8y zgS64;*1}0$5qYcP+m$*mGU$5$KL0#S>#t>R2RB4p10&pInPTt=(%*q>lB~+iR9P;U zgS82FovhIGyixl+!oa=Zb@YVr@0E5<;CvvVuX{?uU+Fc>|Kt&j936v|4Sr@Yz`pw^ zehL>`oTyOYG#XWvK1dZ?K$C!-&S8Sh7r3^6b_@9RiD})VROjqIzMX*%27A+FV|s!J zx=-{GJh_;6!_a{qRfeP9bL=3YGs3LRgfHttY=C)hhG)P!P2}gBb`n_!eqY$beTG^f zHQfNHS*beccoebNTPq>62&Jbcl?v3(Q zidBL+ae6T))|=;u4^l0M&h?gq-O>?-o9ghJ+$iyH#-FFc1|hdT)7(sdwjZl)14P`~ z?Z&V54OOx3JMZ2x#1&HL|CnB4aA{Rn2J;ZZjFu@KQq39HPPJ}5s_nisBd%`L9d=xd z4be`fgIjx|2!zDh*N$qkQ+qf=Iq%!;nHyaBtqk6%=j@f+pA<2d z6-chq9BuS-v$ZXpxihl~+ppvajCy?($&%6*HES0e=Ro(QX2`ZBgG1l)W)!O~cPtUE zTmaLQ-Id(dy8nzYbK_S=<_^v|>v71ZJ?BNaQg*`yj-Mhi7?)x;&$`bzQi`Y98U4TO zT|-{wZQz&Q?R@DS#(&bguiH(^GFIOh5xXF6@Ppt-ZSC0}vGEm0@@90`j2J}YhMGq- z*DRahht9rk6YxFsv*q3ClhkZ_GTX5f1lpg;j67B~WGPq=M#z{IE-%&Q8<(tq8-j~EX*PsOl0WIN<;Ao|!GiGRGJg+f(noD={RnEVD-K2t ztc!N8%$3(g5LE2t@h^yK-ldE7E3{Htka*Ez~I;5MLTlS{yiypL3ikmLi(DrYpX=a;q( z*kBhIDg0bnef@eMlt$Nrz`mzG9LzEGn_=zG|W zAvLc*PgRw}9f`jv9iPSsuK5xyFQS7bxM8fMOcg8yGZ_8k5A8D(P}(StF{lX2P85bJ ziCDM9KJPS#F7itZwMf(|VphoP;6q0`UY5jkGs9g;XTsO@qT|!?!u@f>ak_0r5CYff zO0REDS#`uTC3NbXX#`j&QmdJ=^OHh}0>@&|v>ZP1=9y7nSZM7*8ntV_auQLWC}-=y zU_jrbAwqdR$s(W~&V18fNmw{z@BKryC10ca*NN&`h-%eAtuiqsJZPe^i{_kb6$P|~ z)5_f7G#T!%Hl{h#!ePHH|CDqU%$-caqLzVR1t54L+PGEt!rF`VK~>by=#s`Ln41q; zM_YDNcABf-(zXwW+?k+mdY?rDW+^$8Uj(Kx~%L!1H?KJgymi&ludI8qJgDML%L}_d-&M- zKCEzj2s3mx_ctPYT?o{ztBLm=fMZjjdv%y^^rqV4wCgafu8X`r;^+>i0Nm!aZkY`( zK{Is#u>+EZuE#76Mx;|ia5*O-|QR1r>6D4-cdm{=oXe~C1P`d1-AO)*nH_y9#J8Z3`+B#k%!}Id2alpX4=_4Le zx_Z8GObD&c(Yy<5hpPBHp8A70M~;oWq7-RgT#4}Y{OOO28$9(UP^0;X56>ruV*|c@ zF-y~te#J|L_(f1VyUki%ybNd{2Q_k)mDQ!%zpXp@?5246|9ZL3s3x|yJ0UdbN|lZj zLAn71=?X#sX%~?yO+u9-ND+~Mbfg98O{ECZrAiGTAkrlCjtbJd6sceM)ECXwyY8=h zSZA$dF?-Ks=FB;no&D_U#RKL-x}7wb%!?7qE1NoLdak9UqFdqiZCPSx316EQB?Udd z^lp5DQ9H+GH*MB(6$J}3n$2b5fmeGljoM{XNLfihc>h%253ER7&L>W1oHU7-v>CUzl8;^pe_rgPq4yxo_DmGQrR=%! zt^Mn{`sL5{vUx~f_LVU$D`jXh&@dedE)yD}Z|wK=N90~$`tl^4HycdT$1~CIy_(Mi zGzsLU%)PE@NFya2ATYo(lCR)$KbB)KR6=3lj-Izu)19>AH`fF zY~P&}hj)!l^7P_g8z`JXPj_)>p&vn;f6fQF!n&*YEexL&h+WH{Du^Icy{p!pW2U%b zB4ZY75QnrG1*S%tZ=yTW=^4iK+!Os@s3yx#|>?O z-)_+-Wt50-R!GyFn>+O(#HWggn$Hd{a^9EO-~kbSN+^mS$0O!K@fW}P`v3q(;F9!0K9YAECO^xrGSq zr4eO^@MpcSP-MsS+FC%*yIR_1x+f5*J{C1v8YqfLgQdePf*B-u}&MB%ElO`Q=$JwK_f`XMy zA=6ML^S=mFT527phYJ+SdR7I z*!mz=o$a^h0dJoxoYwgJZ4?2?cI!ysO((*(f9y(-Xu-P z*E6rKwyY3$ief`7K&{?>9nDT^_yxa5|}Zw*m8A^Thb6A=e3JnJZ&*)3KqEYn`%0{Gz@29 z!ivEx;f?;K#&e%zJnaL%CPNYQah$PxJ(eW>3(_89&@xs}@;KeL;-+Oh9*0}dT_F_d zaHxMy-@x{iQ)8pOGHa!Wv-AC@x9TANg;%$%N!1Bbz_&gBglGqpDrHy8qvr!Oy>*{5G!8uag71)CB?oGiqK zNllD~o*hm%oUbRjkN-h7oryQ9ldS@GuN&~1J@xFhTr%a5ph!Q@z`{)yPZH6G!~3r? z&i7Y=0j#a$K{_5!zhZ+&MW|FWdv-=LNK<(z|QQ^G=ve2mn&J(~>5u&N$1m+&xEvkB~y zb*iqj;=cCNy!SbF&tHg6exg)vY7|^^nrmC!ol9^v>1u_SgY9DLrk%?7`7)#Ji0B9> zkbv8VHg4_NpO>BaRowgSXs2Zhy8nII`EIyu0g3(_!{wir9nd1$jJXIJPbQQ4m&*=F z?z?p}Tw3{x2}QHl%nhQ3K&*gSaG=3^6+UNK>r>Va1WDFbfwfSZtNO|wzBV?ca^oz# zzR#f!S*`xeCENFDzxa=S$(I^&KTMjTj}uP+;GWYwY@nq+2qFPNp63(R)-i3eHw|<9 zg$~m8-SqBd<2sdY_FVfJOwNT;s@V^gU6S9dg(zxLCwBl3Uf6vIemd>mCQFu-H6Mx8 zAN6tdzJ7X$yMLjv@KbtjDZdQIJ`%WCWVop-U%S4!>-o0B;v$TPC_>;U%?n>{(w_cmzPUj{o&77f2FMVjUw8Hc@^FNe)Ye*F|UHF|BV~-Pgfs2h<0iY zg6tH`(Dw0v^%#bQ{O;?F7Pq9(pzyDAvJevVsie}w*E^-;e95GkE+Q)=!^h7w!_Uu> zMdzy`E2p*(GZhupbGDCQ3Lb3PHwr4JM-A5jWl9PrX3I0hb}BA2-CIp z@`gQXlc{C_hxkmgIh35fORh7-*{z`GCu|sG?S><9rbI~(RRKzL-Lh)WKeq|s5eXD` zZOS!fYqeb2neBpnt$-f*G{PZq6r*Q|d{5nCi^@^%Oa^Z~naou4O;nc!zO*jl!{ZGT zxMJ0ur#Hy^-WEXO`-850a66?6+}T$dJ#&EFp3lPY@&QALwAVwv$CndS?Gt$@_-Jzz z_lzdL;%0vC@dC$S@hVj)!;pt)b)@$;^;;8YIO`=+(=7?$LG+r_C1f5EExYRG2na`*)9QCY?V?KOzmwF z?Q|1i%bt2VzE_l+0)mJ=9G}S~)5^3kF3X@QkdV4H0%ue3;B2I)DMahaP@BZl zf~dY|kr|PMse{+nMFP*#tsa?1XT+~BE{=6ZMy_4EzTZ+8%G9ll@2jkO_UO-d-pf4; z$wsvJQH$=B=*@oeTB@N-SHCMDwb-)%u>vCgT>;TCv^0>Xk+g6z3*@pRZ`$31$;w~I z)Ohmro|7v};O=d#+G+MIEdoEP5dM5=%lbO1{X9jc;0*lQKxWuB>`@hVcZspSEQPJy zY1$H);F|eL`x=X@iT?0nO_i%Y)0RX>d$JSk^TUZt8y$e;m-kmmZ=O-n%+=w6Jr?v} zyMy8LVDY+KF1a-0>wNfiQNI}ai%=f-B{om&=h zg8;)uGTB=1utaU>g80-Go#$-?dXWvys!m6 zpxxja@((7MBELw%_xQTmlb8LEL}zLhGc&8}P(~o>|cS(@9d-@+R$F?OuZrJoZ zfa(jPmP5R6nzVLmb~aQcor+kNS0jXsopqo8LJNzk&;Lw5r%a z`qf67eMMSWNQsEvB!sY?Wls#Y138pwu(&JJ-!&klF}v+>nBUE{o9xsUO3=C{I>n5i zzr%-Zrc$F3BUDsaC_omC{!yA{!cVbTQbO+oBcN>J?sn(S(p=UX5uT@Z^tZ!l%)*2& zu%)IZC)aSDbG?DW3v_ISUJe8?o9ERKBUelgDzz@$b9QtrnjRBR?7;o{;P5PB8*8WR zh8HvlPY{4lJxPBA*owXn)63g3e{C>M;kV*G9%Nm*3&39hy&^O(xcRUFE`$fDy2mnN zO4laG$;oLX4WEJlC$?>x1V`2ZuQjb=C!ET2!b=r(=*#htMOE>#>fOxj4y9c!Q~)r_r+8rfxj;wq%T7ebMD?V7pnW&#PBp0Ubj)l_&l3wr$CiHmV|X20#Dkeb!Ew_FU$pM z3%4&O=joSs8WtMY7wCp{m~)9Rn$V0#ef|t$>)@gaDTfJXN}mE*mkwLOwg88V?;}g2 za#zPmfpUxNv*^pk2k~Hxi_TbGmO**z+FXX7U*oTEN5buksfZsj$63L27hv`Hh0S8y z!P^f*(remtBTA#x5t+JxNc<2h(iQ1GzE|ZPwq&-CRl%)nVG?7?6~sP9`ha*8oBl~a z&)gaKCaes<;;iVyYSox}tvu}NglxA!#CO>Eh_%eyb{ zGP)w8xIw^x$e?)(4~f3%`n0;>!mu*j3a_NCOYD-`oD?Yw3k!R%De-Iu@|Us(76t_L z#JBA1qJ+eg8tRV7q2|VGI(LwL8Wc4#&9bF>l2x|~Ch+JbwX5POUs&Vr6Y&Taw?q*m zsO(289J?F*2)*oYRBL9_e@?0*74@Pve8i=T+p$Oj-3DZ%hQI?cN*MwAeRmR;UBTq{ zKP3g9U9F90V4bs9OGV_XIc?Iw|8^f zc^VlRnStOlM-*%$DDJN~hgn*;Tgi>05;cFs)ZGUpgOfFC zR9UeoTgN8HB$uz6b`Tkq2cnYvb8L^Li;GLOeJpOdfHsg(aj7bDH7D- ze=RN2I>6%g?Kdx8kGHQYgN*6CQXTbCc8(SiSa)@+&D5|V%D5ik_4V~yUNXZJ08cp} zI#UV17R9wVH#a053d7Bj$(MH!Sv4=_C2Ab95`u90d`@!8CTL|7jp^RruUj4OQfAfR zq|n4cHot8fYvqD%sTRwk#H_F(ir)LyfI7a9@m~%75FsIF(;T1pUN}8ihQ7rDYehKz zHq15sy>cp+EZGzl03~FXjHh|ySE{%4g^Jw^>y{!U)4&2yk8tKJ%x~p@=oeY{y#zN` zSxS8FN|m1Wf5KCfZIv|P7GT+o~w&Xey-L9!#vAt8ehGq);Bykp`l%InnDS)vxj6JQemK?w`BqxH?e#oueJKfvQIv%+!q(W> zSf0K`!A>niu#1N6AYU)fB`iMAx=91q7E-*B>@*NRBxqJbrygB$G3-+*#G-S*qN>Vc z?Vdcm`^M zlorD-XgT6fN;$Tm0C)iXe-yg^W)b5jr*t9wJlmc4A(lz>gp;Y6y%@S70Ubc@N}Cr?ZQRhbLx8*5KeJ_s z(JNZV4T-Eqs`#2zT(D|U&Y^#83D{^*+|kbII}e8y>#j@uO|Ijyyy8MyK?bbo|$&rkGSl-K!!_| zB$HXPszuUX)I3tG9BXv@e$56m{zU*?uSS{#7_kl`t==(VwaL6z=Nv85%ku;#w)uC_ zrNt=r_nYt!6yEHRHU$mmnIv%_A3(2E=N+)UV%=ac@ggVYRIP|NvxAH;gc3~lvE&Vc zx*7drvi>|0+7BPy(?d%aH_-hzBjLM#aRdDFKh`f$KlF<(8!cCgCg~X%2M6V~_UG*Q zF6=s4{WriFMWHK+*9i@^3`z;9HL0)MEUV;_GobWE$x|CDhH&NK;!qx$W)4 zB-2t3mwi{2PuINr_|f!^v-204RntfS>M?q704mu)9$vwH**9;2Y&~}yaOJ<^k)3r5 zXYj@o38372n&wknx}FIb;lKQdSI2eRzGLyat27J-c##sk99Y0ZdYF)`Sayq$*8L@usEz{2k;J`LK?V>i;G>?6%!K^ zJxkedywgTjzOXrP!y$UCBYlO@^f4>2d|1e2Z)TQO;7wze@dN}JS!CQhltvH4rvw$< z@iWiJ%qZYhOp7gaS|B7bP30-}B^*YefR~?t<{-wZe8i84h}bpNWt$s7f1KB4W!g(k z`i6#{Y*r*XT|F21i~NB2p*G|SA`@NDdZ`1p5tMiN(k1FBHZj(@8P<=8GkxXl1p zX$rGyTnQ|xx33oO*W8kRACkz{nn%_kjyyeC-Xiqs6(xXdmkJiV72!T9pN_QP zUa1$wkR#*u#LzmdC0S5UPtW$#9^ZRPk4;GxQTj*?W3>;=aG~o)uG^l-w^U8Z?%vC_ zsxLt0m6nM^edsb{Z4L6SHQP^K7lv2>Af6tb7xDA73_@Fv(7NFt!tsx{{r`FV_yzDw zRKB|Muh8QSevbJ*e*djGqVMhFnACql9EX0Nv}iQq|K*gQA-{_NKZblezRK@AL8l*n z3k3fedYm17yy=hQJI<{=X_4ri{}khj3B(MYJ_df6j-1Q;9mEkpAm$6u&0=S`#(tP3F80& diff --git a/crx/0.1.2_0.pem b/crx/0.1.2_0.pem deleted file mode 100644 index 6b412b5..0000000 --- a/crx/0.1.2_0.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4DYEiDPfw094p -axusu7+kP9J9waL3+794PORnMoBnoKEBuEAfeWLZPtX338nq3dmyiVvNsNKFimcH -vVFye5uHdFOfXZ7f6oIBzeY0616dhcASjV7nj0HkuhDhZQGvBWegQrFJrQQDG99T -kXv3mH8e4W6qvwpyRedXqQJC3gE0LOKvUGlWABQwwq9NF5Uf6vJyXYMv7uBMwpWc -liAtJ6v9742IIGjmZhhaQELliOUucbaeilzxJ29XyVXGhEXNERAXbswSGectHvoz -HsBo4YVzKaR2b8wRXGT1W7am1MwFmOzZcX8tQAXTnoThsAL5tLHi+HJ5QRNbSf6h -C44x8bcdAgMBAAECggEAW+G5/pK00FAkj06+MRxFTqzh2w/o2J2f91mGuJH4kkMZ -Pa+Kq2vA0i1RSf45YfvAqyVxZB0K68mtJ6r2Vw2oFhYXjO6C2svKfTYZ339E66SS -v3A92aGlxpawyKTRE1vCYLoKoXozD45BjgmJ9o/1nifyRGE8yNFm7VcdHt6PgUix -914dJWeSwF94tnRqPJwfOXJkpTXdiWQunGWBOH2nK6y/r2xlLiR4EXDA/4LwMegh -5XHWA4YOG0jQc5a/U5w+899/JKvduo5ZU738jKrtcqD8b2G76R+VTxzbv11ROm6E -AMo1nTHRtbPAKDbSSPWgrzjxQPVGbJPJ+BnzF2V3rQKBgQDnC8OxPuhFvEdjmijW -1lPWkB4NBJ9uBtWEMhHe5PTeHs0sfm9AZvM8npObMNcOvmQH3bGX2aY9XoEHZbjK -ixM5miVazdEt0y7UonzcXqjpOvjiqlaAcMP+2Y6ejqi1JD3sflyi/GmLNCtlbRsZ -Fx7sgPNk+LueGvwK35TWIsL7hwKBgQDL7mpjYk5V3osb1AGqcaJYsVa9Qm2izsAl -g13sxollDLazaitwAt3r+FMtLVgJPptTlV37QF1WbSCfGCYjjFRP0WQN1lTlZqUN -4QNKQ6SI/Wp4qjl127T2n/1toc7Mhjs00V+RJiFYpN5cdvXniBXjJC0oh30tL+L8 -Cvws2QYJOwKBgQDJEqD1QSUNg4SxdvkxtwbxhSzR8YL6UzJAwP5yd9lu8Wln3oTd -jHsE95DID6Ipr6IIgnRLDdyyLeumz20ZwB00FSWLN/FiqxZncR2u/yaLC4qMYOe1 -Ee5QfW+0J71FH8xQY8wk//yua/GUbHaXyFpeQv8PkbReLWfJ4rh5/3inQwKBgQCl -7M9dG6BXF6Ihu0a7soeAGJJVnRXtUMFgBFnIi+VAda61nh3Hnl2IYFz0th8aLnlc -8XwtMLqA1nujVpe5drUm2FzLMWeT2wdSmpD9vLnDyET39rCX53J+87/UksHbASBt -IinaxKZ/JG3T1+rOPphoXofroQnFWWAa6KkzqETT/wKBgDv2KDnZqYMSNy4xtz96 -IdOpYioocSvRS5kUUwokAIU9CYIo5+iyaJYok25u6OaRNOr1vqzqeG5j8Rdc/kQc -70df/gZ2Gejn+3BYJtwtgeB25KfCjd+jhTHOOgLbnK0tX3h8X5wkpA0628inwMhg -Q9GxE6HDisGIr0S5PWnZFh34 ------END PRIVATE KEY----- diff --git a/crx/myblock.crx b/crx/myblock.crx new file mode 100644 index 0000000000000000000000000000000000000000..6ee88c65bb208fc887b525118235a905a7b66f8f GIT binary patch literal 75903 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%0D6oB*g(UWl_1TJl-pA57Fl|~h32#Et9 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 a$xVmf?SKTk1OWh)u%FAT_&dtWzW6_aV@`Mg literal 0 HcmV?d00001 diff --git a/crx/myblock.pem b/crx/myblock.pem new file mode 100644 index 0000000..605b6cf --- /dev/null +++ b/crx/myblock.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDSG09DSvB03TOe +eOmQwfiCIf0wa2WRB31ewxa6i/PRgEKeJSUvIsIuaECUer2ss+J3rwSS2lDpGuiw +FnsVyZqKI/+Rcuc83YJGYg6OAzVMz6UL8YCWhXu3huTJ+V+a5iNereIC69ZERRJt +nXlWqsq6HKya+6BP9sX9CI4GTHQrnWBysAxsswhdnnnRvu+GxglWafSIzuS6OizT +1M1CmkZxNvDJhTSOR7SJlIYm2kM5/fIL53BdndF2IGAjfV1WV7AjwhTfun5cViEO +i8niQUIMY4L0AiO9grFD1g1xIYkeuVBoLxOUBzPxJwQmb64gseb9Dvt0BKLRGoou +SIOyE+KVAgMBAAECggEAI4b6J2kR0VUBEDwmVHO0K38HUstqNHSVgrNO0dLt8sAz +I44o5DhGqPW4a9L4ZS5SrkWyKonPcic6buISRIwfPVoacjQBfVWAXJnil6lbtyYK +ZMNcqLcgBRfCcpOgEq91DiKta6yIwekDFXVyCdFd78v+9ML1J+hUsLVkXJTLdP88 +PGamRWVd6vGy3QMRjyM29GLPgS+/6Vrp1cptSuYNqYhlszohmu8lBvzjH9jbPh9d +GFrrd8Bs7IRCdtKZig/3fbln4JEyyOYE+gcT2jplPksB6mR/5DBIdkVbeuFwGB0+ +h1/PKlprNQt7+Ei0HhHnTib7lZP8WGo4HkSi7PsAGQKBgQD1Ptho0wJiI2+6gL1O +iNsEJVKIQ2Sxdx3wI/qudphM99t6xKCpPyVI2Nd9PBf2jbZjGAaz+P/KQYxEqb6i +PRcQ+i99wCQoRfnRvUbKA4goEpKwRXmvn+499dm6D5pEuumOXGQYCmaFXuLTRN/I +BL6GNgLtoZAlLjUXaWtk8TszGQKBgQDbUf3p3HLpCjRvRDW/vA5xj+08t7xtF9uO +NilGK79uOA4VnxE2w3ioYqQ7t3I8J/0rAzGKq3tylg4QX6UpQ4b2koRr2B3cqoAk +dsRdNWAHwCNepz8hTLsZyuihzbNv2nHmoqhzjK/FcrBHx5NAM+T6OBpLzQBnbUzk +3wIcqm223QKBgQDo/IRxyY0pGMtLXoT6ODACF0b6JzRhGG37tuKvngGAlbQQRP7w +6wmL1F2cH1wQon7UU34CupqfVnhgvvZZgToJqfU2PTTcgeYc6Pl4b7SJhWOQTOCX +BZQ7jvYCulHv27aIxaNd53uQVx2cYoFKr58lN+i+QtADUoujq0YYxshb+QKBgQDW +ZOti7kZCeuBRGIu2V56C8uBFp5MBzf2polZsqx1iIFfcWPfZ4fGUIYFMgwKfvbOl +lWSbmxB9LiSnaugoU0OezBG43rYqXV4Qxy0jtKagTPoGcFWtNrX7+7e3XD8Zi6Am +hkFHW3MEAB5EvNq8Oz6OP8Os78SCVn2BimMlJJFF3QKBgQCF+aEAiBv+ivcmHUeP +2eBq9nLltPFAfXJ/p31MMQ6Jgo36DBqUeoLeyq/WfIXvwqbVbP9fANZrKoTPbI97 +dilCHUoO33rafXJy6jtaggtpz14tt9soecTop0vM/rU7tGtfBe6NXg9LRl+oDJCU +37I3a9Is+2CLyAUXWCk9mLfFsQ== +-----END PRIVATE KEY----- diff --git a/extractor/openrec_extractor/main.go b/extractor/openrec_extractor/main.go index 2fb7715..4596421 100644 --- a/extractor/openrec_extractor/main.go +++ b/extractor/openrec_extractor/main.go @@ -1,7 +1,6 @@ package main import ( - "net/http" _ "net/http/pprof" ) @@ -16,10 +15,6 @@ import ( */ func main() { - go func() { - http.ListenAndServe("0.0.0.0:8899", nil) - }() - oe := &OpenrecExtractor{} oe.Execute() } diff --git a/extractor/openrec_extractor/openrec_extractor.go b/extractor/openrec_extractor/openrec_extractor.go index 6052389..45f751e 100644 --- a/extractor/openrec_extractor/openrec_extractor.go +++ b/extractor/openrec_extractor/openrec_extractor.go @@ -39,27 +39,9 @@ func (oe *OpenrecExtractor) Execute() { }() var lasterr error = nil - execute := func() bool { + for atomic.LoadInt32(&loop) > 0 { var err error - // if sstore.PopCount() >= 1000 { - // if err = estore.Close(); err != nil { - // log.Println(err) - // } - // if err = sstore.Close(); err != nil { - // log.Println(err) - // } - // estore = intimate.NewStoreExtractor() - // sstore = intimate.NewStoreSource(string(intimate.STOpenrec)) - - // oe.supporters.Clear() - // oe.user.Clear() - // oe.userLive.Clear() - - // runtime.GC() // 主动gc - // log.Println("1000次执行, gc 重新建立sql链接") - // } - source, err := sstore.Pop(intimate.TOpenrecUser, 0) if err != nil { if err != lasterr { @@ -67,7 +49,7 @@ func (oe *OpenrecExtractor) Execute() { lasterr = err } time.Sleep(time.Second * 2) - return true + continue } sdata := source.Ext.([]byte) @@ -118,15 +100,8 @@ func (oe *OpenrecExtractor) Execute() { source.Operator = int32(intimate.OperatorExtractorOK) sstore.UpdateOperator(source) - - return true } - for atomic.LoadInt32(&loop) > 0 { - if !execute() { - break - } - } } func (oe *OpenrecExtractor) extractFollowers(clog intimate.ISet) { diff --git a/extractor/twitch_extractor/.gitignore b/extractor/twitch_extractor/.gitignore new file mode 100644 index 0000000..a2523a9 --- /dev/null +++ b/extractor/twitch_extractor/.gitignore @@ -0,0 +1,4 @@ +*.html +log +screenlog.* +twitch_extractor \ No newline at end of file diff --git a/extractor/twitch_extractor/twitch_test.go b/extractor/twitch_extractor/twitch_test.go new file mode 100644 index 0000000..884215e --- /dev/null +++ b/extractor/twitch_extractor/twitch_test.go @@ -0,0 +1,13 @@ +package main + +import ( + "intimate" + "testing" +) + +var estore = intimate.NewStoreExtractor() +var sstore = intimate.NewStoreSource(string(intimate.STOpenrec)) + +func TestCase0(t *testing.T) { + +} diff --git a/go.mod b/go.mod index 729309d..28e095a 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.14 require ( github.com/474420502/gcurl v0.1.2 github.com/474420502/hunter v0.3.4 + github.com/474420502/requests v1.6.0 github.com/go-sql-driver/mysql v1.5.0 github.com/lestrrat-go/libxml2 v0.0.0-20200215080510-6483566f52cb github.com/tebeka/selenium v0.9.9 diff --git a/tasks/openrec/openrec_task1/task_openrec.go b/tasks/openrec/openrec_task1/task_openrec.go index feeeb60..124be92 100644 --- a/tasks/openrec/openrec_task1/task_openrec.go +++ b/tasks/openrec/openrec_task1/task_openrec.go @@ -70,12 +70,12 @@ func (or *OpenrecRanking) Execute(cxt *hunter.TaskContext) { tp := cxt.Temporary() content := resp.Content() - if len(content) <= 200 { // 末页退出 + if len(content) <= 200 { //末页时没有内容返回, 末页退出 finishpoint := time.Now() log.Println("任务Ranking UserId结束休眠, 下次启动时间:", finishpoint.Add(time.Minute*120)) for time.Now().Sub(finishpoint) < time.Minute*120 { time.Sleep(time.Second) - if atomic.LoadInt32(&loop) > 0 { + if atomic.LoadInt32(&loop) <= 0 { return } } @@ -122,6 +122,7 @@ func (or *OpenrecRanking) Execute(cxt *hunter.TaskContext) { } } + // 修改url query 参数的page递增. 遍历所有页面 querys := tp.GetQuery() page, err := strconv.Atoi(querys.Get("page")) if err != nil { diff --git a/tasks/openrec/openrec_task2/task_openrec.go b/tasks/openrec/openrec_task2/task_openrec.go index 76ea4c8..9126949 100644 --- a/tasks/openrec/openrec_task2/task_openrec.go +++ b/tasks/openrec/openrec_task2/task_openrec.go @@ -51,7 +51,7 @@ func (oer *OpenrecExtratorRanking) Execute(cxt *hunter.TaskContext) { for atomic.LoadInt32(&loop) > 0 { - streamer, err := estore.Pop(intimate.Popenrec) + streamer, err := estore.Pop(intimate.Popenrec) //队列里弹出一个streamer行. 进行解析 if streamer == nil || err != nil { if err != lasterr { @@ -66,7 +66,7 @@ func (oer *OpenrecExtratorRanking) Execute(cxt *hunter.TaskContext) { var updateUrl map[string]string - err = json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) + err = json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) // 反序列化update_url, 里面存了需要采集的url if err != nil { log.Println(err) continue @@ -74,7 +74,7 @@ func (oer *OpenrecExtratorRanking) Execute(cxt *hunter.TaskContext) { // Check Userid userUrl := updateUrl["user"] - tp := cxt.Session().Get(userUrl) + tp := cxt.Session().Get(userUrl) // 获取user url页面数据 resp, err := tp.Execute() streamer.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} @@ -86,14 +86,14 @@ func (oer *OpenrecExtratorRanking) Execute(cxt *hunter.TaskContext) { cookies := cxt.Session().GetCookies(tp.GetParsedURL()) - scurl := updateUrl["supporters"] + scurl := updateUrl["supporters"] //获取打赏者的数据 curl := gcurl.ParseRawCURL(scurl) supportersSession := curl.CreateSession() temporary := curl.CreateTemporary(supportersSession) supportersSession.SetCookies(temporary.GetParsedURL(), cookies) var supporters []string - for { + for { // supporters 数据需要登录信息. 下面为赋值 supporters链接获取的uid token random码 supportersQuery := temporary.GetQuery() @@ -122,13 +122,13 @@ func (oer *OpenrecExtratorRanking) Execute(cxt *hunter.TaskContext) { log.Println(err) } supporterjson := gjson.ParseBytes(resp.Content()) - supporterdata := supporterjson.Get("data") + supporterdata := supporterjson.Get("data") //解析supporters获取的json数据 if supporterdata.Type == gjson.Null { break } supporters = append(supporters, string(resp.Content())) - page := supportersQuery.Get("page_number") + page := supportersQuery.Get("page_number") // page_number 加1 pageint, err := strconv.Atoi(page) if err != nil { log.Println(err) diff --git a/tasks/twitch/twitch_task1/.gitignore b/tasks/twitch/twitch_task1/.gitignore new file mode 100644 index 0000000..3684d9b --- /dev/null +++ b/tasks/twitch/twitch_task1/.gitignore @@ -0,0 +1,2 @@ +twitch_task1 +log \ No newline at end of file diff --git a/tasks/twitch/twitch_task1/task_twitch.go b/tasks/twitch/twitch_task1/task_twitch.go index cdff148..bc7805d 100644 --- a/tasks/twitch/twitch_task1/task_twitch.go +++ b/tasks/twitch/twitch_task1/task_twitch.go @@ -25,6 +25,7 @@ type ChannelLink struct { func (cl *ChannelLink) Execute() { var err error wd := intimate.GetChromeDriver(3030) + defer wd.Close() weburl := "https://www.twitch.tv/directory?sort=VIEWER_COUNT" err = wd.Get(weburl) diff --git a/tasks/twitch/twitch_task2/.gitignore b/tasks/twitch/twitch_task2/.gitignore new file mode 100644 index 0000000..846a6b4 --- /dev/null +++ b/tasks/twitch/twitch_task2/.gitignore @@ -0,0 +1,2 @@ +twitch_task2 +log \ No newline at end of file diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go index 178f0b8..7b721a5 100644 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ b/tasks/twitch/twitch_task2/task_twitch.go @@ -33,6 +33,7 @@ func (cl *UserList) Execute() { //article//a[@data-a-target='preview-card-title-link'] wd := intimate.GetChromeDriver(3030) + defer wd.Close() var loop int32 = 1 @@ -74,19 +75,20 @@ func (cl *UserList) Execute() { var elements []selenium.WebElement var liveurls = 0 - var delayerror = 3 + var delayerror = 2 for i := 0; i < 200 && atomic.LoadInt32(&loop) > 0; i++ { elements, err = wd.FindElements(selenium.ByXPATH, "(//div/p[@class=''])[last()]") if err != nil { log.Println(err) break } + time.Sleep(time.Millisecond * 500) wd.KeyDown(selenium.EndKey) wd.KeyUp(selenium.EndKey) - time.Sleep(time.Second * 2) + time.Sleep(time.Millisecond * 1500) if len(elements) == liveurls { if liveurls == 0 { - delayerror -= 2 + delayerror -= 1 } else { delayerror-- } @@ -95,7 +97,7 @@ func (cl *UserList) Execute() { break } } else { - delayerror = 3 + delayerror = 2 } liveurls = len(elements) } diff --git a/tasks/twitch/twitch_task3/task_twitch_test.go b/tasks/twitch/twitch_task3/task_twitch_test.go new file mode 100644 index 0000000..2c6c19a --- /dev/null +++ b/tasks/twitch/twitch_task3/task_twitch_test.go @@ -0,0 +1,114 @@ +package main + +import ( + "encoding/json" + "intimate" + "log" + "os" + "os/signal" + "regexp" + "sync/atomic" + "syscall" + "testing" + "time" + + "github.com/tebeka/selenium" +) + +// sstore 源存储实例, 为存储源数据的实现. 表格具体参考sql/intimate_source.sql +var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwitch)) + +// estore 解析存储连接实例 +var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() + +func TestCase(t *testing.T) { + var loop int32 = 1 + wd := intimate.GetChromeDriver(3030) + + go func() { + signalchan := make(chan os.Signal) + signal.Notify(signalchan, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP) + log.Println("accept stop command:", <-signalchan) + atomic.StoreInt32(&loop, 0) + }() + + var lasterr error = nil + // var err error + + for atomic.LoadInt32(&loop) > 0 { + streamer, err := estore.Pop(intimate.Ptwitch, 0) + if streamer == nil || err != nil { + if err != lasterr { + log.Println(err, lasterr) + lasterr = err + } + time.Sleep(time.Second * 2) + continue + } + + var updateUrl map[string]string + json.Unmarshal(streamer.UpdateUrl.([]byte), &updateUrl) + liveUrl := updateUrl["live"] + log.Println(liveUrl) + + err = wd.Get("https://www.twitch.tv/zoe_0601" + "/about") + if err != nil { + log.Println(err) + //estore.UpdateError(streamer, err) + continue + } + + time.Sleep(time.Millisecond * 500) + wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + _, err = web.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1/text()") + if err != nil { + return false, err + } + return true, err + }, 12) + + label, err := wd.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1") + if err != nil { + log.Println(err) + //estore.UpdateError(streamer, err) + continue + } + log.Println(label.Text()) + + wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + followers, err := web.FindElement(selenium.ByXPATH, "//div[@data-a-target='about-panel']//div[@class='tw-align-center']/text()") + if err != nil { + return false, err + } + ft, err := followers.Text() + log.Println(ft) + if err != nil || ft != "" { + return false, err + } + return true, nil + }, 12) + + followers, err := wd.FindElement(selenium.ByXPATH, "//div[@data-a-target='about-panel']//div[@class='tw-align-center']") + if err != nil { + log.Println(err) + //estore.UpdateError(streamer, err) + continue + } + fstr, err := followers.Text() + if err != nil { + log.Println(err) + //estore.UpdateError(streamer, err) + continue + } + log.Println(regexp.MustCompile(`[\d,]+`).FindString(fstr)) + //div[@data-a-target="about-panel"] + + if views, err := wd.FindElement(selenium.ByXPATH, "//a[@data-a-target='home-live-overlay-button']/span"); err == nil { + log.Println(views.Text()) + views.Click() + } + + streamer.Operator = 0 + estore.UpdateOperator(streamer) + } +} diff --git a/utils.go b/utils.go index 774de66..899b68d 100644 --- a/utils.go +++ b/utils.go @@ -51,11 +51,11 @@ func ParseDuration(dt string) (time.Duration, error) { func GetChromeDriver(port int) selenium.WebDriver { caps := selenium.Capabilities{"browserName": "chrome"} chromecaps := chrome.Capabilities{} - err := chromecaps.AddExtension("../../../crx/0.1.2_0.crx") + err := chromecaps.AddExtension("../../../crx/myblock.crx") if err != nil { panic(err) } - chromecaps.Args = append(chromecaps.Args, "--proxy-pac-url=http://127.0.0.1:1081/pac") + // chromecaps.Args = append(chromecaps.Args, "--proxy-pac-url=http://127.0.0.1:1081/pac") chromecaps.Args = append(chromecaps.Args, "--disk-cache-dir=/tmp/chromedriver-cache") chromecaps.ExcludeSwitches = append(chromecaps.ExcludeSwitches, "enable-automation") caps.AddChrome(chromecaps) From ac1ab81676f7a2745b0b442c889325f59483804c Mon Sep 17 00:00:00 2001 From: eson Date: Tue, 28 Jul 2020 18:56:27 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=AE=8C=E6=88=90twitch=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8F=90=E5=8F=96=E5=85=A5=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tasks/twitch/twitch_task1/task_twitch.go | 54 +++-- tasks/twitch/twitch_task2/task_twitch.go | 14 +- tasks/twitch/twitch_task3/task_twitch_test.go | 201 ++++++++++++++---- utils.go | 8 + 4 files changed, 212 insertions(+), 65 deletions(-) diff --git a/tasks/twitch/twitch_task1/task_twitch.go b/tasks/twitch/twitch_task1/task_twitch.go index bc7805d..18b852d 100644 --- a/tasks/twitch/twitch_task1/task_twitch.go +++ b/tasks/twitch/twitch_task1/task_twitch.go @@ -49,22 +49,51 @@ func (cl *ChannelLink) Execute() { } e.Click() + var hrefs map[string]bool = make(map[string]bool) + var delayerror = 5 + var samecount = 0 for i := 0; i <= 200; i++ { - wd.KeyDown(selenium.EndKey) - time.Sleep(time.Second * 2) - } - - elements, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") - if err != nil { - panic(err) - } - // xpath: //article//a[@data-a-target='preview-card-title-link'] - for _, ele := range elements { - href, err := ele.GetAttribute("href") + cards, err := wd.FindElements(selenium.ByXPATH, "//span/a[contains(@data-a-target,'card-') and @href]") if err != nil { log.Println(err) + break } - log.Println(href) // TODO: Save href + + if len(cards) == samecount { + delayerror-- + if delayerror <= 0 { + break + } + } else { + delayerror = 5 + } + + for _, card := range cards { + href, err := card.GetAttribute("href") + if err != nil { + log.Println(err) + } else { + hrefs[href] = true + } + } + samecount = len(cards) + + if len(cards) > 10 { + log.Println(len(cards)) + wd.ExecuteScript(`items = document.evaluate("//div[@data-target='directory-page__card-container']/../self::div[@data-target and @style]", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0; i < items.snapshotLength - 10; i++) { item = items.snapshotItem(i); item.remove() ;};`, nil) + } + time.Sleep(time.Millisecond * 200) + wd.KeyDown(selenium.EndKey) + time.Sleep(time.Millisecond * 200) + wd.KeyUp(selenium.EndKey) + time.Sleep(time.Millisecond * 2500) + + } + + for href := range hrefs { + + // TODO: Save href source := &intimate.Source{} source.Source = sql.NullString{String: href, Valid: true} source.Operator = 0 @@ -73,5 +102,6 @@ func (cl *ChannelLink) Execute() { sstore.Insert(source) } + log.Println("hrefs len:", len(hrefs)) sstore.Deduplicate(intimate.TTwitchChannel, "source") } diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go index 7b721a5..c64ef1d 100644 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ b/tasks/twitch/twitch_task2/task_twitch.go @@ -36,6 +36,7 @@ func (cl *UserList) Execute() { defer wd.Close() var loop int32 = 1 + var count = 0 go func() { signalchan := make(chan os.Signal) @@ -87,12 +88,7 @@ func (cl *UserList) Execute() { wd.KeyUp(selenium.EndKey) time.Sleep(time.Millisecond * 1500) if len(elements) == liveurls { - if liveurls == 0 { - delayerror -= 1 - } else { - delayerror-- - } - + delayerror-- if delayerror <= 0 { break } @@ -140,5 +136,11 @@ func (cl *UserList) Execute() { estore.InsertStreamer(streamer) } log.Println("streamer insert", len(elements)) + count++ + if count >= 100 { + wd.Close() + wd = intimate.GetChromeDriver(3030) + count = 0 + } } } diff --git a/tasks/twitch/twitch_task3/task_twitch_test.go b/tasks/twitch/twitch_task3/task_twitch_test.go index 2c6c19a..db7b37b 100644 --- a/tasks/twitch/twitch_task3/task_twitch_test.go +++ b/tasks/twitch/twitch_task3/task_twitch_test.go @@ -1,6 +1,7 @@ package main import ( + "database/sql" "encoding/json" "intimate" "log" @@ -51,64 +52,170 @@ func TestCase(t *testing.T) { liveUrl := updateUrl["live"] log.Println(liveUrl) - err = wd.Get("https://www.twitch.tv/zoe_0601" + "/about") + // err = wd.Get("https://www.twitch.tv/zoe_0601" + "/about") + err = wd.Get(liveUrl + "/about") if err != nil { log.Println(err) //estore.UpdateError(streamer, err) continue } + streamer.LiveUrl = sql.NullString{String: liveUrl, Valid: true} + clog := &intimate.CollectLog{} + clog.UserId = streamer.UserId + time.Sleep(time.Millisecond * 500) - wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { - _, err = web.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1/text()") - if err != nil { - return false, err - } - return true, err - }, 12) + extractUserName(wd, streamer) + extractFollowers(wd, clog) + err = extractViews(wd, clog) // views + tags + gratuity - label, err := wd.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1") if err != nil { - log.Println(err) - //estore.UpdateError(streamer, err) - continue - } - log.Println(label.Text()) + // 不直播时提取礼物 gratuity + wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + channelchat, err := wd.FindElement(selenium.ByXPATH, `//a[@data-a-target="channel-home-tab-Chat"]`) + btn, _ := web.FindElement(selenium.ByXPATH, `//button[@data-test-selector="expand-grabber"]`) + if (err == nil && channelchat != nil) || btn != nil { + if channelchat != nil { + channelchat.Click() + } + time.Sleep(time.Second) + extractGratuity(wd, clog) + return true, nil + } + return false, nil - wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { - followers, err := web.FindElement(selenium.ByXPATH, "//div[@data-a-target='about-panel']//div[@class='tw-align-center']/text()") - if err != nil { - return false, err - } - ft, err := followers.Text() - log.Println(ft) - if err != nil || ft != "" { - return false, err - } - return true, nil - }, 12) - - followers, err := wd.FindElement(selenium.ByXPATH, "//div[@data-a-target='about-panel']//div[@class='tw-align-center']") - if err != nil { - log.Println(err) - //estore.UpdateError(streamer, err) - continue - } - fstr, err := followers.Text() - if err != nil { - log.Println(err) - //estore.UpdateError(streamer, err) - continue - } - log.Println(regexp.MustCompile(`[\d,]+`).FindString(fstr)) - //div[@data-a-target="about-panel"] - - if views, err := wd.FindElement(selenium.ByXPATH, "//a[@data-a-target='home-live-overlay-button']/span"); err == nil { - log.Println(views.Text()) - views.Click() + }, time.Second*4) } - streamer.Operator = 0 - estore.UpdateOperator(streamer) + streamer.Platform = intimate.Ptwitch + clog.Platform = string(streamer.Platform) + clog.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} + lastClogId := estore.InsertCollectLog(clog) + + streamer.Operator = 100 + streamer.LatestLogUid = lastClogId + estore.UpdateStreamer(streamer) + } } + +func extractUserName(wd selenium.WebDriver, streamer *intimate.Streamer) error { + return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + label, err := web.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1") + if err == nil { + if ltxt, err := label.Text(); err == nil { + log.Println("label:", ltxt) + streamer.UserName = sql.NullString{String: ltxt, Valid: true} + return true, nil + } + } + return false, err + }, 6*time.Second) +} + +func extractFollowers(wd selenium.WebDriver, clog *intimate.CollectLog) error { + return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + efollowers, err := web.FindElement(selenium.ByXPATH, "//div[@data-a-target='about-panel']//div[@class='tw-align-center']") + if err != nil { + return false, err + } + followers, err := efollowers.Text() + if err != nil || followers == "" { + return false, err + } + followers = regexp.MustCompile(`[\d,]+`).FindString(followers) + fint, _ := intimate.ParseNumber(followers) + clog.Followers = sql.NullInt64{Int64: int64(fint), Valid: true} + log.Println("followers: ", followers, fint) + return true, nil + }, 6*time.Second) +} + +func extractViews(wd selenium.WebDriver, clog *intimate.CollectLog) error { + return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + views, err := web.FindElement(selenium.ByXPATH, "//a[@data-a-target='home-live-overlay-button']/span") + if views != nil { + if txt, err := views.Text(); err == nil { + + vint, _ := intimate.ParseNumber(txt) + clog.Views = sql.NullInt64{Int64: vint, Valid: true} + log.Println("views:", txt) + views.Click() + + extractTags(wd, clog) + extractTitle(wd, clog) + extractGratuity(wd, clog) + + return true, nil + } + } + return false, err + }, time.Second*4) +} + +func extractTitle(wd selenium.WebDriver, clog *intimate.CollectLog) error { + return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + title, err := web.FindElement(selenium.ByXPATH, `//h2[@data-a-target='stream-title']`) + if err == nil { + if txt, err := title.Text(); err == nil { + clog.LiveTitle = sql.NullString{String: txt, Valid: true} + return true, nil + } + } + return false, err + }, time.Second*4) +} + +func extractTags(wd selenium.WebDriver, clog *intimate.CollectLog) error { + return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + tags, err := web.FindElements(selenium.ByXPATH, "//a[@aria-label and @data-a-target and @href]/div[@class and text()]") + if len(tags) == 0 { + return false, err + } + + var stags []string + for _, tag := range tags { + if txt, err := tag.Text(); err == nil { + stags = append(stags, txt) + } else { + log.Println(err) + } + log.Println(tag.Text()) + } + if len(stags) > 0 { + if tagbuf, err := json.Marshal(stags); err == nil { + clog.Tags = tagbuf + } else { + log.Println(err) + } + } + + return true, nil + }, time.Second*4) +} + +func extractGratuity(wd selenium.WebDriver, clog *intimate.CollectLog) error { + return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { + btn, err := web.FindElement(selenium.ByXPATH, `//button[@data-test-selector="expand-grabber"]`) + if err == nil { + btn.Click() + time.Sleep(time.Second) + gifcount, err := web.FindElements(selenium.ByXPATH, `//div[@class="sub-gift-count tw-flex"]/p`) + if err == nil { + var gratuity int64 = 0 + for _, gc := range gifcount { + if gtxt, err := gc.Text(); err == nil { + gint, _ := intimate.ParseNumber(gtxt) + gratuity += gint + } else { + log.Println(err) + } + } + clog.Gratuity = sql.NullInt64{Int64: gratuity, Valid: true} + } + return true, nil + } + + return false, err + }, time.Second*4) +} diff --git a/utils.go b/utils.go index 899b68d..39f1d19 100644 --- a/utils.go +++ b/utils.go @@ -4,6 +4,8 @@ import ( "fmt" "log" "runtime" + "strconv" + "strings" "time" "github.com/tebeka/selenium" @@ -22,6 +24,12 @@ func init() { } +// ParseNumber 去逗号解析数字 +func ParseNumber(number string) (int64, error) { + number = strings.ReplaceAll(number, ",", "") + return strconv.ParseInt(number, 10, 64) +} + // ParseDuration time to duration eg: 1:40:00 -> time.Duration func ParseDuration(dt string) (time.Duration, error) { From 0c54cbf8d8ab15ec3b7f4c58c7743e79d0edae5d Mon Sep 17 00:00:00 2001 From: eson Date: Fri, 31 Jul 2020 18:04:10 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=AE=8C=E6=88=90twitch=E7=9A=84=E6=9C=9F?= =?UTF-8?q?=E6=9C=9B=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- config.go | 2 +- .../openrec_extractor/openrec_extractor.go | 5 +- .../twitch_extractor/tiwtch_extractor.go | 82 ++++++--- extractor/twitch_extractor/twitch_test.go | 6 +- extractor_field.go | 5 +- go.mod | 1 + sql/intimate_extractor.sql | 1 + store.go | 43 +++-- tasks/twitch/twitch_task1/task_twitch.go | 24 ++- tasks/twitch/twitch_task2/task_twitch.go | 101 +++++++---- utils.go | 160 +++++++++++++++++- xvfb.sh | 1 + 13 files changed, 334 insertions(+), 100 deletions(-) rename tasks/twitch/twitch_task3/task_twitch_test.go => extractor/twitch_extractor/tiwtch_extractor.go (80%) create mode 100644 xvfb.sh diff --git a/.gitignore b/.gitignore index 1796cca..657f5f1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ intimate *.gz debug.test myblock - +run.sh +stop.sh diff --git a/config.go b/config.go index 1e73967..369ca21 100644 --- a/config.go +++ b/config.go @@ -17,7 +17,7 @@ func init() { InitConfig.Load() // storeOpenrec = NewStore() - log.SetFlags(log.Llongfile | log.Ldate) + log.SetFlags(log.Llongfile | log.Ltime) } // Config 配置 diff --git a/extractor/openrec_extractor/openrec_extractor.go b/extractor/openrec_extractor/openrec_extractor.go index 45f751e..3b689ad 100644 --- a/extractor/openrec_extractor/openrec_extractor.go +++ b/extractor/openrec_extractor/openrec_extractor.go @@ -48,7 +48,7 @@ func (oe *OpenrecExtractor) Execute() { log.Println(err, lasterr) lasterr = err } - time.Sleep(time.Second * 2) + time.Sleep(time.Second * 5) continue } @@ -85,12 +85,13 @@ func (oe *OpenrecExtractor) Execute() { streamer.Uid = source.StreamerId.Int64 streamer.UpdateTime = source.UpdateTime + streamer.Tags = clog.Tags clog.Platform = string(intimate.Popenrec) clog.UserId = userId clog.UpdateTime = source.UpdateTime - logUid := estore.InsertCollectLog(clog) + logUid := estore.InsertClog(clog) LiveUrl := "https://www.openrec.tv/live/" + userId streamer.LiveUrl = sql.NullString{String: LiveUrl, Valid: true} diff --git a/tasks/twitch/twitch_task3/task_twitch_test.go b/extractor/twitch_extractor/tiwtch_extractor.go similarity index 80% rename from tasks/twitch/twitch_task3/task_twitch_test.go rename to extractor/twitch_extractor/tiwtch_extractor.go index db7b37b..bd2c6cf 100644 --- a/tasks/twitch/twitch_task3/task_twitch_test.go +++ b/extractor/twitch_extractor/tiwtch_extractor.go @@ -5,12 +5,7 @@ import ( "encoding/json" "intimate" "log" - "os" - "os/signal" "regexp" - "sync/atomic" - "syscall" - "testing" "time" "github.com/tebeka/selenium" @@ -22,21 +17,24 @@ var sstore *intimate.StoreSource = intimate.NewStoreSource(string(intimate.STTwi // estore 解析存储连接实例 var estore *intimate.StoreExtractor = intimate.NewStoreExtractor() -func TestCase(t *testing.T) { - var loop int32 = 1 +func main() { wd := intimate.GetChromeDriver(3030) + ps := intimate.NewPerfectShutdown() - go func() { - signalchan := make(chan os.Signal) - signal.Notify(signalchan, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP) - log.Println("accept stop command:", <-signalchan) - atomic.StoreInt32(&loop, 0) - }() + counter := intimate.NewCounter() + counter.SetMaxLimit(200) + counter.SetMaxToDo(func(olist ...interface{}) error { + owd := olist[0].(*selenium.WebDriver) + (*owd).Close() + (*owd).Quit() + *owd = intimate.GetChromeDriver(3030) + return nil + }, &wd) var lasterr error = nil // var err error - for atomic.LoadInt32(&loop) > 0 { + for !ps.IsClose() { streamer, err := estore.Pop(intimate.Ptwitch, 0) if streamer == nil || err != nil { if err != lasterr { @@ -56,19 +54,27 @@ func TestCase(t *testing.T) { err = wd.Get(liveUrl + "/about") if err != nil { log.Println(err) - //estore.UpdateError(streamer, err) + estore.UpdateError(streamer, err) + time.Sleep(time.Second * 5) continue } streamer.LiveUrl = sql.NullString{String: liveUrl, Valid: true} clog := &intimate.CollectLog{} clog.UserId = streamer.UserId + clog.Gratuity = sql.NullInt64{Int64: 0, Valid: false} time.Sleep(time.Millisecond * 500) - extractUserName(wd, streamer) - extractFollowers(wd, clog) - err = extractViews(wd, clog) // views + tags + gratuity + err = extractUserName(wd, streamer) + if err != nil { + continue + } + err = extractFollowers(wd, clog) + if err != nil { + continue + } + err = extractViews(wd, clog) // views + tags + gratuity if err != nil { // 不直播时提取礼物 gratuity wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { @@ -90,27 +96,48 @@ func TestCase(t *testing.T) { streamer.Platform = intimate.Ptwitch clog.Platform = string(streamer.Platform) clog.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} - lastClogId := estore.InsertCollectLog(clog) + lastClogId := estore.InsertClog(clog) - streamer.Operator = 100 + streamer.Operator = 10 streamer.LatestLogUid = lastClogId - estore.UpdateStreamer(streamer) + if clog.Tags != nil { + streamer.Tags = clog.Tags + } + switch fl := clog.Followers.Int64; { + case fl > 100000: + streamer.UpdateInterval = 120 + case fl > 10000: + streamer.UpdateInterval = 240 + case fl > 1000: + streamer.UpdateInterval = 360 + case fl > 100: + streamer.UpdateInterval = 720 + case fl > 0: + streamer.UpdateInterval = 1440 + } + + streamer.UpdateTime = clog.UpdateTime + estore.UpdateStreamer(streamer) + counter.AddWithReset(1) } + + wd.Close() + wd.Quit() } func extractUserName(wd selenium.WebDriver, streamer *intimate.Streamer) error { return wd.WaitWithTimeout(func(web selenium.WebDriver) (bool, error) { label, err := web.FindElement(selenium.ByXPATH, "//a[@class='tw-interactive']//h1") if err == nil { - if ltxt, err := label.Text(); err == nil { - log.Println("label:", ltxt) + if ltxt, err := label.Text(); err == nil && ltxt != "" { + // log.Println("label:", ltxt) streamer.UserName = sql.NullString{String: ltxt, Valid: true} return true, nil } } return false, err - }, 6*time.Second) + }, 15*time.Second) } func extractFollowers(wd selenium.WebDriver, clog *intimate.CollectLog) error { @@ -126,9 +153,9 @@ func extractFollowers(wd selenium.WebDriver, clog *intimate.CollectLog) error { followers = regexp.MustCompile(`[\d,]+`).FindString(followers) fint, _ := intimate.ParseNumber(followers) clog.Followers = sql.NullInt64{Int64: int64(fint), Valid: true} - log.Println("followers: ", followers, fint) + // log.Println("followers: ", followers, fint) return true, nil - }, 6*time.Second) + }, 4*time.Second) } func extractViews(wd selenium.WebDriver, clog *intimate.CollectLog) error { @@ -139,7 +166,7 @@ func extractViews(wd selenium.WebDriver, clog *intimate.CollectLog) error { vint, _ := intimate.ParseNumber(txt) clog.Views = sql.NullInt64{Int64: vint, Valid: true} - log.Println("views:", txt) + // log.Println("views:", txt) views.Click() extractTags(wd, clog) @@ -180,7 +207,6 @@ func extractTags(wd selenium.WebDriver, clog *intimate.CollectLog) error { } else { log.Println(err) } - log.Println(tag.Text()) } if len(stags) > 0 { if tagbuf, err := json.Marshal(stags); err == nil { diff --git a/extractor/twitch_extractor/twitch_test.go b/extractor/twitch_extractor/twitch_test.go index 884215e..731b2d3 100644 --- a/extractor/twitch_extractor/twitch_test.go +++ b/extractor/twitch_extractor/twitch_test.go @@ -1,13 +1,9 @@ package main import ( - "intimate" "testing" ) -var estore = intimate.NewStoreExtractor() -var sstore = intimate.NewStoreSource(string(intimate.STOpenrec)) - func TestCase0(t *testing.T) { - + main() } diff --git a/extractor_field.go b/extractor_field.go index 0f94cd6..ad5ef30 100644 --- a/extractor_field.go +++ b/extractor_field.go @@ -19,11 +19,12 @@ type Streamer struct { UserName sql.NullString // LiveUrl sql.NullString // Channel sql.NullString // - Ext interface{} // + Tags interface{} + Ext interface{} // IsUpdateStreamer bool // 更新上面的内容 IsUpdateUrl bool - updateInterval int32 + UpdateInterval int32 UpdateUrl interface{} LatestLogUid int64 UpdateTime sql.NullTime // diff --git a/go.mod b/go.mod index 28e095a..d8b824d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module intimate go 1.14 require ( + github.com/474420502/focus v0.12.0 github.com/474420502/gcurl v0.1.2 github.com/474420502/hunter v0.3.4 github.com/474420502/requests v1.6.0 diff --git a/sql/intimate_extractor.sql b/sql/intimate_extractor.sql index f588757..91d3e3b 100644 --- a/sql/intimate_extractor.sql +++ b/sql/intimate_extractor.sql @@ -8,6 +8,7 @@ CREATE TABLE IF NOT EXISTS `streamer` ( `user_name` varchar(255) DEFAULT NULL COMMENT '用户名字 区别于ID', `live_url` text COMMENT '直播的url', `channel` varchar(128) DEFAULT NULL COMMENT'所属 频道,分类 未必所有平台都有明确的标签', + `tag` json DEFAULT NULL COMMENT 'streamer 最新的tag', `ext` json DEFAULT NULL COMMENT '扩展类型, 把一些可能需要但是没字段的数据放在json扩展', `is_update_streamer` tinyint(1) DEFAULT 0 COMMENT '是否需要持续更新streamer的信息. 1为需要,0则否', diff --git a/store.go b/store.go index 45f7f06..cbdbbfc 100644 --- a/store.go +++ b/store.go @@ -230,7 +230,7 @@ func (store *StoreExtractor) Pop(platform Platform, operators ...int32) (*Stream return nil, err } var args = []interface{}{string(platform)} - selectSQL := `select uid, update_time, user_id, update_url, is_update_streamer from ` + StreamerTable + ` where platform = ? and TIMESTAMPDIFF(MINUTE , update_time, CURRENT_TIMESTAMP()) >= update_interval` + selectSQL := `select uid, update_time, user_id, update_url, is_update_streamer, update_interval from ` + StreamerTable + ` where platform = ? and TIMESTAMPDIFF(MINUTE , update_time, CURRENT_TIMESTAMP()) >= update_interval` if len(operators) == 0 { selectSQL += " and operator = ?" args = append(args, 0) @@ -258,7 +258,7 @@ func (store *StoreExtractor) Pop(platform Platform, operators ...int32) (*Stream s := &Streamer{} // uid, url, target_type, source, ext, operator - err = row.Scan(&s.Uid, &s.UpdateTime, &s.UserId, &s.UpdateUrl, &s.IsUpdateStreamer) + err = row.Scan(&s.Uid, &s.UpdateTime, &s.UserId, &s.UpdateUrl, &s.IsUpdateStreamer, &s.UpdateInterval) if err != nil { return nil, err } @@ -270,7 +270,7 @@ func (store *StoreExtractor) Pop(platform Platform, operators ...int32) (*Stream // InsertStreamer Streamer表, 插入数据 func (store *StoreExtractor) InsertStreamer(streamer IGet) (isExists bool) { // select uid from table where platform = ? and user_id = ? - selectSQL := "SELECT is_update_url FROM " + StreamerTable + " WHERE platform = ? AND user_id = ?" + selectSQL := "SELECT is_update_url, uid FROM " + StreamerTable + " WHERE platform = ? AND user_id = ?" tx, err := store.db.Begin() if err != nil { panic(err) @@ -289,14 +289,16 @@ func (store *StoreExtractor) InsertStreamer(streamer IGet) (isExists bool) { row := tx.QueryRow(selectSQL+` LIMIT 1 FOR UPDATE`, streamer.Get("Platform"), streamer.Get("UserId")) var isUpdateUrl bool - if err = row.Scan(&isUpdateUrl); err == nil { + var Uid int64 + if err = row.Scan(&isUpdateUrl, &Uid); err == nil { if isUpdateUrl { tx.Exec("UPDATE "+StreamerTable+" SET update_url = ?", streamer.Get("UpdateUrl")) } + streamer.(ISet).Set("Uid", Uid) return true } - _, err = tx.Exec("INSERT INTO "+StreamerTable+"(platform, user_id, update_url, update_time) VALUES(?,?,?,?);", streamer.Get("Platform"), streamer.Get("UserId"), streamer.Get("UpdateUrl"), time.Now().Add(-time.Minute*30)) + _, err = tx.Exec("INSERT INTO "+StreamerTable+"(platform, user_id, update_url, update_time) VALUES(?,?,?,?);", streamer.Get("Platform"), streamer.Get("UserId"), streamer.Get("UpdateUrl"), time.Now().Add(-time.Minute*60)) if err != nil { panic(err) } @@ -331,16 +333,33 @@ func (store *StoreExtractor) UpdateOperator(isource IGet) { } // UpdateStreamer Streamer表, 插入数据 -func (store *StoreExtractor) UpdateStreamer(isource IGet) { - _, err := store.db.Exec("UPDATE "+StreamerTable+" SET user_name = ?, live_url = ?, channel = ?, latest_log_uid = ?, ext = ?, operator = ?, update_time = ? WHERE uid = ?;", - isource.Get("UserName"), isource.Get("LiveUrl"), isource.Get("Channel"), isource.Get("LatestLogUid"), isource.Get("Ext"), isource.Get("Operator"), isource.Get("UpdateTime"), isource.Get("Uid")) +func (store *StoreExtractor) UpdateStreamer(streamer IGet) { + _, err := store.db.Exec("UPDATE "+StreamerTable+" SET user_name = ?, live_url = ?, channel = ?, latest_log_uid = ?, tags = ?, ext = ?, operator = ?, update_time = ?, update_interval = ? WHERE uid = ?;", + streamer.Get("UserName"), streamer.Get("LiveUrl"), streamer.Get("Channel"), streamer.Get("LatestLogUid"), streamer.Get("Tags"), streamer.Get("Ext"), streamer.Get("Operator"), streamer.Get("UpdateTime"), streamer.Get("UpdateInterval"), streamer.Get("Uid")) if err != nil { panic(err) } } -// InsertCollectLog CollectLog表插入数据 -func (store *StoreExtractor) InsertCollectLog(isource IGet) int64 { +// Update Streamer表, 更新指定的字段 +func (store *StoreExtractor) Update(streamer IGet, fieldvalues ...interface{}) { + updateSQL := "UPDATE " + StreamerTable + " SET " + var values []interface{} + for i := 0; i < len(fieldvalues); i += 2 { + field := fieldvalues[i] + values = append(values, fieldvalues[i+1]) + updateSQL += field.(string) + " = ? " + } + updateSQL += "WHERE uid = ?" + values = append(values, streamer.Get("Uid")) + _, err := store.db.Exec(updateSQL, values...) + if err != nil { + panic(err) + } +} + +// InsertClog CollectLog表插入数据 +func (store *StoreExtractor) InsertClog(clog IGet) int64 { tx, err := store.db.Begin() defer func() { @@ -355,7 +374,7 @@ func (store *StoreExtractor) InsertCollectLog(isource IGet) int64 { } result, err := tx.Exec("insert into "+CollectLogTable+"(streamer_uid, platform, user_id, is_live_streaming, is_error, followers, views, giver, gratuity, live_title, live_start_time, live_end_time, update_time, tags, ext, error_msg) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", - isource.Get("StreamerUid"), isource.Get("Platform"), isource.Get("UserId"), isource.Get("IsLiveStreaming"), isource.Get("IsError"), isource.Get("Followers"), isource.Get("Views"), isource.Get("Giver"), isource.Get("Gratuity"), isource.Get("LiveTitle"), isource.Get("LiveStartTime"), isource.Get("LiveEndTime"), isource.Get("UpdateTime"), isource.Get("Tags"), isource.Get("Ext"), isource.Get("ErrorMsg"), + clog.Get("StreamerUid"), clog.Get("Platform"), clog.Get("UserId"), clog.Get("IsLiveStreaming"), clog.Get("IsError"), clog.Get("Followers"), clog.Get("Views"), clog.Get("Giver"), clog.Get("Gratuity"), clog.Get("LiveTitle"), clog.Get("LiveStartTime"), clog.Get("LiveEndTime"), clog.Get("UpdateTime"), clog.Get("Tags"), clog.Get("Ext"), clog.Get("ErrorMsg"), ) if err != nil { panic(err) @@ -366,7 +385,7 @@ func (store *StoreExtractor) InsertCollectLog(isource IGet) int64 { panic(err) } - _, err = tx.Exec("update "+StreamerTable+" set latest_log_uid = ? where uid = ?", logUid, isource.Get("StreamerUid")) + _, err = tx.Exec("update "+StreamerTable+" set latest_log_uid = ? where uid = ?", logUid, clog.Get("StreamerUid")) if err = tx.Commit(); err != nil { panic(err) } diff --git a/tasks/twitch/twitch_task1/task_twitch.go b/tasks/twitch/twitch_task1/task_twitch.go index 18b852d..2b385ed 100644 --- a/tasks/twitch/twitch_task1/task_twitch.go +++ b/tasks/twitch/twitch_task1/task_twitch.go @@ -25,7 +25,7 @@ type ChannelLink struct { func (cl *ChannelLink) Execute() { var err error wd := intimate.GetChromeDriver(3030) - defer wd.Close() + ps := intimate.NewPerfectShutdown() weburl := "https://www.twitch.tv/directory?sort=VIEWER_COUNT" err = wd.Get(weburl) @@ -40,7 +40,7 @@ func (cl *ChannelLink) Execute() { } return len(elements) > 0, nil } - wd.WaitWithTimeout(cardCondition, time.Second*30) + wd.WaitWithTimeout(cardCondition, time.Second*15) time.Sleep(time.Second) e, err := wd.FindElement(selenium.ByXPATH, "//button[@data-a-target='browse-sort-menu']") @@ -68,15 +68,22 @@ func (cl *ChannelLink) Execute() { delayerror = 5 } - for _, card := range cards { - href, err := card.GetAttribute("href") - if err != nil { - log.Println(err) - } else { - hrefs[href] = true + for ii := 0; ii < 10; ii++ { + for _, card := range cards { + href, err := card.GetAttribute("href") + if err != nil { + log.Println(href, err) + continue + } else { + hrefs[href] = true + } } + break } samecount = len(cards) + if ps.IsClose() { + break + } if len(cards) > 10 { log.Println(len(cards)) @@ -88,7 +95,6 @@ func (cl *ChannelLink) Execute() { time.Sleep(time.Millisecond * 200) wd.KeyUp(selenium.EndKey) time.Sleep(time.Millisecond * 2500) - } for href := range hrefs { diff --git a/tasks/twitch/twitch_task2/task_twitch.go b/tasks/twitch/twitch_task2/task_twitch.go index c64ef1d..52773de 100644 --- a/tasks/twitch/twitch_task2/task_twitch.go +++ b/tasks/twitch/twitch_task2/task_twitch.go @@ -5,11 +5,7 @@ import ( "encoding/json" "intimate" "log" - "os" - "os/signal" "regexp" - "sync/atomic" - "syscall" "time" "github.com/tebeka/selenium" @@ -33,19 +29,18 @@ func (cl *UserList) Execute() { //article//a[@data-a-target='preview-card-title-link'] wd := intimate.GetChromeDriver(3030) - defer wd.Close() + ps := intimate.NewPerfectShutdown() + counter := intimate.NewCounter() + counter.SetMaxLimit(100) + counter.SetMaxToDo(func(olist ...interface{}) error { + owd := olist[0].(*selenium.WebDriver) + (*owd).Close() + (*owd).Quit() + *owd = intimate.GetChromeDriver(3030) + return nil + }, &wd) - var loop int32 = 1 - var count = 0 - - go func() { - signalchan := make(chan os.Signal) - signal.Notify(signalchan, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP) - log.Println("accept stop command:", <-signalchan) - atomic.StoreInt32(&loop, 0) - }() - - for atomic.LoadInt32(&loop) > 0 { + for !ps.IsClose() { var err error sourceChannel, err := sstore.Pop(intimate.TTwitchChannel) @@ -56,7 +51,10 @@ func (cl *UserList) Execute() { weburl := sourceChannel.Source.String + "?sort=VIEWER_COUNT" err = wd.Get(weburl) if err != nil { - panic(err) + log.Println(err) + sstore.UpdateError(sourceChannel, err) + time.Sleep(time.Second * 10) + continue } wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) { @@ -77,16 +75,17 @@ func (cl *UserList) Execute() { var elements []selenium.WebElement var liveurls = 0 var delayerror = 2 - for i := 0; i < 200 && atomic.LoadInt32(&loop) > 0; i++ { + for i := 0; i < 200 && !ps.IsClose(); i++ { elements, err = wd.FindElements(selenium.ByXPATH, "(//div/p[@class=''])[last()]") if err != nil { log.Println(err) break } - time.Sleep(time.Millisecond * 500) + time.Sleep(time.Millisecond * 200) wd.KeyDown(selenium.EndKey) + time.Sleep(time.Millisecond * 200) wd.KeyUp(selenium.EndKey) - time.Sleep(time.Millisecond * 1500) + time.Sleep(time.Millisecond * 2000) if len(elements) == liveurls { delayerror-- if delayerror <= 0 { @@ -97,34 +96,62 @@ func (cl *UserList) Execute() { } liveurls = len(elements) } - elements, err = wd.FindElements(selenium.ByXPATH, "//article//a[@data-a-target='preview-card-title-link' and @href]") + articles, err := wd.FindElements(selenium.ByXPATH, "//article") if err != nil { log.Println(err) continue } - for _, e := range elements { + for _, article := range articles { - attr, err := e.GetAttribute("href") + e, err := article.FindElement(selenium.ByXPATH, ".//a[@data-a-target='preview-card-title-link' and @href]") if err != nil { log.Println(err) continue } + + href, err := e.GetAttribute("href") + if err != nil { + log.Println(err) + continue + } + + btns, err := article.FindElements(selenium.ByXPATH, ".//div[@class='tw-full-width tw-inline-block']//button") + if err != nil { + log.Println(err) + continue + } + + var tags []string + for _, btn := range btns { + tag, err := btn.GetAttribute("data-a-target") + if err == nil { + tags = append(tags, tag) + } + } + streamer := &intimate.Streamer{} - matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(attr) + matches := regexp.MustCompile(`https://www.twitch.tv/(\w+)`).FindStringSubmatch(href) if len(matches) == 2 { streamer.UserId = matches[1] } else { - log.Println(attr) + log.Println(href) continue } + jtags, err := json.Marshal(tags) + if err != nil { + log.Println(err) + } else { + streamer.Tags = jtags + } + streamer.Platform = intimate.Ptwitch updateUrl := make(map[string]string) - updateUrl["live"] = attr - streamer.LiveUrl = sql.NullString{String: attr, Valid: true} + updateUrl["live"] = href + streamer.LiveUrl = sql.NullString{String: href, Valid: true} data, err := json.Marshal(updateUrl) if err != nil { log.Println(err) @@ -132,15 +159,19 @@ func (cl *UserList) Execute() { } streamer.UpdateUrl = data streamer.Operator = 0 - - estore.InsertStreamer(streamer) + if estore.InsertStreamer(streamer) { + // log.Println("streamer update tags", streamer.Uid, tags) + estore.Update(streamer, "Tags", streamer.Tags) + } } - log.Println("streamer insert", len(elements)) - count++ - if count >= 100 { - wd.Close() - wd = intimate.GetChromeDriver(3030) - count = 0 + log.Println("streamer find", len(articles)) + if len(articles) == 0 { + sourceChannel.Operator = 5 + sstore.UpdateOperator(sourceChannel) } + counter.AddWithReset(1) } + + wd.Close() + wd.Quit() } diff --git a/utils.go b/utils.go index 39f1d19..ebee59b 100644 --- a/utils.go +++ b/utils.go @@ -3,9 +3,13 @@ package intimate import ( "fmt" "log" + "os" + "os/signal" "runtime" "strconv" "strings" + "sync/atomic" + "syscall" "time" "github.com/tebeka/selenium" @@ -50,21 +54,44 @@ func ParseDuration(dt string) (time.Duration, error) { tdt, err := time.Parse("15:04:05", string(parse)) if err != nil { - return time.Duration(0), err } return tdt.Sub(zeroTime), nil } func GetChromeDriver(port int) selenium.WebDriver { + var err error caps := selenium.Capabilities{"browserName": "chrome"} + chromecaps := chrome.Capabilities{} - err := chromecaps.AddExtension("../../../crx/myblock.crx") - if err != nil { - panic(err) + for _, epath := range []string{"../../../crx/myblock.crx", "../../crx/myblock.crx"} { + _, err := os.Stat(epath) + if err == nil { + err := chromecaps.AddExtension(epath) + if err != nil { + panic(err) + } + break + } } + + if proxy := os.Getenv("chrome_proxy"); proxy != "" { + log.Println("proxy-server", proxy) + chromecaps.Args = append(chromecaps.Args, "--proxy-server="+proxy) + } + + if proxy := os.Getenv("pac_proxy"); proxy != "" { + log.Println("--proxy-pac-url=" + proxy) + chromecaps.Args = append(chromecaps.Args, "--proxy-pac-url="+proxy) + } + // chromecaps.Args = append(chromecaps.Args, "--proxy-pac-url=http://127.0.0.1:1081/pac") chromecaps.Args = append(chromecaps.Args, "--disk-cache-dir=/tmp/chromedriver-cache") + chromecaps.Args = append(chromecaps.Args, "--disable-gpu", "--disable-images", "--start-maximized", "--disable-infobars") + // chromecaps.Args = append(chromecaps.Args, "--headless") + chromecaps.Args = append(chromecaps.Args, "--no-sandbox") + chromecaps.Args = append(chromecaps.Args, "--disable-dev-shm-usage", "--mute-audio", "--safebrowsing-disable-auto-update") + chromecaps.ExcludeSwitches = append(chromecaps.ExcludeSwitches, "enable-automation") caps.AddChrome(chromecaps) _, err = selenium.NewChromeDriverService("/usr/bin/chromedriver", port) @@ -76,14 +103,137 @@ func GetChromeDriver(port int) selenium.WebDriver { panic(err) } runtime.SetFinalizer(wd, func(obj interface{}) { - log.Println(obj) + if err := obj.(selenium.WebDriver).Close(); err != nil { log.Println(err) } + if err := obj.(selenium.WebDriver).Quit(); err != nil { + log.Println(err) + } + }) wd.ExecuteScript("windows.navigator.webdriver = undefined", nil) if err != nil { panic(err) } + return wd } + +// PerfectShutdown 完美关闭程序 +type PerfectShutdown struct { + loop int32 +} + +// NewPerfectShutdown 创建完美关闭程序 +func NewPerfectShutdown() *PerfectShutdown { + ps := &PerfectShutdown{} + ps.loop = 1 + + go func() { + signalchan := make(chan os.Signal) + signal.Notify(signalchan, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP) + log.Println("accept stop command:", <-signalchan) + atomic.StoreInt32(&ps.loop, 0) + }() + + return ps +} + +// IsClose 判断是否要关闭 +func (ps *PerfectShutdown) IsClose() bool { + return atomic.LoadInt32(&ps.loop) == 0 +} + +type Counter struct { + dcount int + count int + maxLimit int + minLimit int + + minobj []interface{} + maxobj []interface{} + maxLimitToDo func(obj ...interface{}) error + minLimitToDo func(obj ...interface{}) error +} + +func NewCounter() *Counter { + c := &Counter{} + return c +} + +// SetDefault 设置默认值 +func (c *Counter) SetDefault(n int) { + c.dcount = n +} + +// Reset 最置count为defaultCount值 +func (c *Counter) Reset() { + c.count = c.dcount +} + +// SetCount 设置count到最大值的时候执行do函数 +func (c *Counter) SetCount(count int) { + c.count = count +} + +// GetCount 设置count到最大值的时候执行do函数 +func (c *Counter) GetCount() int { + return c.count +} + +// SetMinLimit 设置最小限制 +func (c *Counter) SetMinLimit(n int) { + c.minLimit = n +} + +// SetMaxLimit 设置最大限制 +func (c *Counter) SetMaxLimit(n int) { + c.maxLimit = n +} + +// SetMaxToDo 设置count到最大值的时候执行do函数 +func (c *Counter) SetMaxToDo(do func(obj ...interface{}) error, obj ...interface{}) { + c.maxLimitToDo = do + c.maxobj = obj +} + +// SetMinToDo 设置count到最小值的时候执行do函数 +func (c *Counter) SetMinToDo(do func(obj ...interface{}) error, obj ...interface{}) { + c.minLimitToDo = do + c.minobj = obj +} + +// AddWithReset 操作 count 默认值为0, 当触发限制时, 重置为默认值 +func (c *Counter) AddWithReset(n int) error { + c.count += n + if c.maxLimitToDo != nil { + if c.count >= c.maxLimit { + defer c.Reset() + return c.maxLimitToDo(c.maxobj...) + } + } + if c.minLimitToDo != nil { + if c.count <= c.minLimit { + defer c.Reset() + return c.minLimitToDo(c.minobj...) + } + } + return nil +} + +// Add 操作 count 默认值为0 +func (c *Counter) Add(n int) error { + c.count += n + if c.maxLimitToDo != nil { + if c.count >= c.maxLimit { + return c.maxLimitToDo(c.maxobj...) + } + } + if c.minLimitToDo != nil { + if c.count <= c.minLimit { + return c.minLimitToDo(c.minobj...) + } + } + return nil +} diff --git a/xvfb.sh b/xvfb.sh new file mode 100644 index 0000000..d5f6036 --- /dev/null +++ b/xvfb.sh @@ -0,0 +1 @@ +screen -dmS xvfb-99 Xvfb :99 -screen 0 1280x720x24 -ac -nolisten tcp -dpi 96 +extension RANDR -nolisten tcp