From 8d4f0614a271d56987fa403c0f6cbaf3c6c891b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E7=A7=8B=E7=8E=B2?= <1969472656@qq.com> Date: Sun, 23 Nov 2025 23:27:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96djangoblog=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- djangoblog-yql(优化后)/__init__.py | 1 + .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 209 bytes .../__pycache__/admin_site.cpython-313.pyc | Bin 0 -> 2766 bytes .../__pycache__/apps.cpython-313.pyc | Bin 0 -> 829 bytes .../__pycache__/blog_signals.cpython-313.pyc | Bin 0 -> 5652 bytes .../elasticsearch_backend.cpython-313.pyc | Bin 0 -> 9564 bytes .../__pycache__/feeds.cpython-313.pyc | Bin 0 -> 2805 bytes .../__pycache__/logentryadmin.cpython-313.pyc | Bin 0 -> 4262 bytes .../__pycache__/settings.cpython-313.pyc | Bin 0 -> 9977 bytes .../__pycache__/sitemap.cpython-313.pyc | Bin 0 -> 3389 bytes .../__pycache__/spider_notify.cpython-313.pyc | Bin 0 -> 1385 bytes .../__pycache__/urls.cpython-313.pyc | Bin 0 -> 3149 bytes .../__pycache__/utils.cpython-313.pyc | Bin 0 -> 11804 bytes .../whoosh_cn_backend.cpython-313.pyc | Bin 0 -> 34851 bytes .../__pycache__/wsgi.cpython-313.pyc | Bin 0 -> 640 bytes djangoblog-yql(优化后)/admin_site.py | 64 + djangoblog-yql(优化后)/apps.py | 11 + djangoblog-yql(优化后)/blog_signals.py | 122 ++ .../elasticsearch_backend.py | 183 +++ djangoblog-yql(优化后)/feeds.py | 40 + djangoblog-yql(优化后)/logentryadmin.py | 91 ++ .../__pycache__/base_plugin.cpython-313.pyc | Bin 0 -> 1959 bytes .../hook_constants.cpython-313.pyc | Bin 0 -> 387 bytes .../__pycache__/hooks.cpython-313.pyc | Bin 0 -> 2336 bytes .../__pycache__/loader.cpython-313.pyc | Bin 0 -> 1545 bytes .../plugin_manage/base_plugin.py | 41 + .../plugin_manage/hook_constants.py | 7 + .../plugin_manage/hooks.py | 44 + .../plugin_manage/loader.py | 19 + .../plugins/reading_time/plugin.py | 17 + .../templates/toc_navigator/toc_sidebar.html | 68 ++ djangoblog-yql(优化后)/settings.py | 344 ++++++ djangoblog-yql(优化后)/sitemap.py | 59 + djangoblog-yql(优化后)/spider_notify.py | 21 + djangoblog-yql(优化后)/tests.py | 32 + djangoblog-yql(优化后)/urls.py | 64 + djangoblog-yql(优化后)/utils.py | 256 ++++ .../whoosh_cn_backend.py | 1045 +++++++++++++++++ .../whoosh_index/MAIN_WRITELOCK | 0 .../whoosh_index/MAIN_cv5z5jbh0nmqme2y.seg | Bin 0 -> 18093 bytes .../whoosh_index/MAIN_frrhzeacoiu5g7bj.seg | Bin 0 -> 6327 bytes .../whoosh_index/MAIN_mwmu9cx1o0vefml0.seg | Bin 0 -> 6327 bytes .../whoosh_index/MAIN_w8vdct7cbhie95f9.seg | Bin 0 -> 136513 bytes .../whoosh_index/_MAIN_38.toc | Bin 0 -> 2327 bytes .../whoosh_index/_MAIN_42.toc | Bin 0 -> 2139 bytes djangoblog-yql(优化后)/wsgi.py | 16 + 46 files changed, 2545 insertions(+) create mode 100644 djangoblog-yql(优化后)/__init__.py create mode 100644 djangoblog-yql(优化后)/__pycache__/__init__.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/admin_site.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/apps.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/blog_signals.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/elasticsearch_backend.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/feeds.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/logentryadmin.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/settings.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/sitemap.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/spider_notify.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/urls.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/utils.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/whoosh_cn_backend.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/__pycache__/wsgi.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/admin_site.py create mode 100644 djangoblog-yql(优化后)/apps.py create mode 100644 djangoblog-yql(优化后)/blog_signals.py create mode 100644 djangoblog-yql(优化后)/elasticsearch_backend.py create mode 100644 djangoblog-yql(优化后)/feeds.py create mode 100644 djangoblog-yql(优化后)/logentryadmin.py create mode 100644 djangoblog-yql(优化后)/plugin_manage/__pycache__/base_plugin.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/plugin_manage/__pycache__/hook_constants.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/plugin_manage/__pycache__/hooks.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/plugin_manage/__pycache__/loader.cpython-313.pyc create mode 100644 djangoblog-yql(优化后)/plugin_manage/base_plugin.py create mode 100644 djangoblog-yql(优化后)/plugin_manage/hook_constants.py create mode 100644 djangoblog-yql(优化后)/plugin_manage/hooks.py create mode 100644 djangoblog-yql(优化后)/plugin_manage/loader.py create mode 100644 djangoblog-yql(优化后)/plugin_manage/plugins/reading_time/plugin.py create mode 100644 djangoblog-yql(优化后)/plugin_manage/plugins/toc_navigator/templates/toc_navigator/toc_sidebar.html create mode 100644 djangoblog-yql(优化后)/settings.py create mode 100644 djangoblog-yql(优化后)/sitemap.py create mode 100644 djangoblog-yql(优化后)/spider_notify.py create mode 100644 djangoblog-yql(优化后)/tests.py create mode 100644 djangoblog-yql(优化后)/urls.py create mode 100644 djangoblog-yql(优化后)/utils.py create mode 100644 djangoblog-yql(优化后)/whoosh_cn_backend.py create mode 100644 djangoblog-yql(优化后)/whoosh_index/MAIN_WRITELOCK create mode 100644 djangoblog-yql(优化后)/whoosh_index/MAIN_cv5z5jbh0nmqme2y.seg create mode 100644 djangoblog-yql(优化后)/whoosh_index/MAIN_frrhzeacoiu5g7bj.seg create mode 100644 djangoblog-yql(优化后)/whoosh_index/MAIN_mwmu9cx1o0vefml0.seg create mode 100644 djangoblog-yql(优化后)/whoosh_index/MAIN_w8vdct7cbhie95f9.seg create mode 100644 djangoblog-yql(优化后)/whoosh_index/_MAIN_38.toc create mode 100644 djangoblog-yql(优化后)/whoosh_index/_MAIN_42.toc create mode 100644 djangoblog-yql(优化后)/wsgi.py diff --git a/djangoblog-yql(优化后)/__init__.py b/djangoblog-yql(优化后)/__init__.py new file mode 100644 index 0000000..1e205f4 --- /dev/null +++ b/djangoblog-yql(优化后)/__init__.py @@ -0,0 +1 @@ +default_app_config = 'djangoblog.apps.DjangoblogAppConfig' diff --git a/djangoblog-yql(优化后)/__pycache__/__init__.cpython-313.pyc b/djangoblog-yql(优化后)/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9674d55664d29f7330db0f9ee78f41b5b28daab0 GIT binary patch literal 209 zcmey&%ge<81n0yLWLN{~#~=<2FhUuhIe?6*48aUV4C#!TOjXJ$S&4b+`AIqX>3WF; z1;u(UaK2+ffpdOdT4uVRCgUxkl+?7u(wvfbprZI>u<%NT&mco@88}ev^oKq zy19wPC8Dz KL8yoY$Oixbl{=6C literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/__pycache__/admin_site.cpython-313.pyc b/djangoblog-yql(优化后)/__pycache__/admin_site.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14bb323d77bbbbd0f3d9ef4a8f8da987f88ccc57 GIT binary patch literal 2766 zcmah~-EY)J5Fg*CbGeU%B=k4}T+)=rAsi4uRZ)u?0;0`DAYr0D)YLL}#xeM8*!2|! zp(;<6cxqpe?y;}@7ySz=A{}b9I;2YN3sN7bf&`D9UHj}nLAH|hZ)ScoJ2N}$+bxv} zfY0wA{kHLK9^fx744-TWcK=BMJO&k1sR^qRk?I_$nyJ+^Nei5AW>&K#D{!WnTg{Wa zz}cq!St>*$5h_GzG(yD?<(j3{GAV~XmB>C8q45aqi_k=bCON9YEU5V!sIn%VO$Sww zDQyb1BWmGuiR{<*Upp}@Gk$AT?Z8>Al|Oa(0H>xMOyo>!hY~r5wIhj~x;B%@nbkf{ z zjQZd}TUc(QrEc)#ZR!)lw>|g4)E*PX^aFb<9C(o=&yfG`&f#)idJNwQHD9i$*5L+z z64s@&QlPAZ1y7_aN{VG^_pV8ptn0X+uj@*hWvJ=gVj0)ym~2GXTaH1gu2UYoUf*I% zE9W$xqZSu(ykk(`BwC!MCJNAbu8q5!q=LR|I(CREZw&XXB7=_M@@5MLa_LciTdwvd zpUH=JQ3r2T%4-mnHV{0P(kn(M6l;qI@nXDZ;mBd1Bt{ zn$)K}K)p^TxU#%qP#yc!u_?v#V6*Ql!Ep+w^!dVjW!lj z5Q1;}jw#wrYCQ2NJUAa`sHGdePwbmr-^82&ouv9A8(IB{mt1M5E>5?Xzz- zM7@Nc9y|CxQv+)^9ZE8sQG18ME2Lov{tNfN5CI_!k>iZA(Q0{J*ALxTflqD_f{h9s zuvxj~bvkBDtVD81s0PUhAB=%ivKdq(^NmJ5qw8;kk&A&4dRDyqNH$t`hDnUYijXpa z1NZ}um*E@I56Pg&~sQ4xQ2KDhX*h-fZ10$SyFn+E5O&k3s9c<)!HsKwhDhj z;SZSDhKXM;_ipsz*iIyW-RtyWF_u?))jrI|@}=InJ{*nZ%RQ|R3$eWRboO)~&cqwM x8}I{!*dd4*%ir{V>_a2oq4{*?R3DaN0xFjJa5`38>?wVii)BpV87ztx{|Eg+y!ikC literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/__pycache__/apps.cpython-313.pyc b/djangoblog-yql(优化后)/__pycache__/apps.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..380c1b7000a8f77f6c75908db4258b4d61f8833c GIT binary patch literal 829 zcmY*X&ui2`6n>K*ZQAZyX;-%`6xJd_K!XP>B5koh@X$gpaZj!evzytNGMmIna;T@C zgn}Lm{tNyW{srQ(4tf#~dlOc%N8cpdRR{9&-hA)9dEYlPs@G=$*T?3E7n=m&n+`6Q zJ$6R7&^ZGid~yK$M3NRP!5a9+3ixJ+teaJyG(yX@hdOYHn%Pd%-6ZZuVXuNKYm9@@ zU38vf*A7VHgEV|1P2Z4~Z%Vrj_lR$;z>y=Td|OVpVUtMbCb&~-aqo!5VbT>zI5}Xb z2Y9s_l!zB}y+IOik$F2&xLxGQ><&~(zW^HP1gQFLU7H)p>B-aYa(F*O+^t#apqde&We;vWlPS2W7VhtI$$vi zxuQ6Q&|}o{W4H9l=cM6GDGWy+&HQ)g{%5E0_R0wN;XSxB%Aqu715T-$ zr4*Gdg!XHczATs+BlDE@BbntQig}zMyb$m{D@0BiUI1eH1}vRi4RsAU)P5<U3mofekU22zj!$)N?5OW*(jnnMq1P#`@OqN#w)R6+v8Zj+l-1x3(Y`ew)_ z71>5QAZOmZdGqG?zPs&mIS`b;H-32aEjL16(2iMzGO%6b5PA(oQIs1+xYTl(V|@$e zp|y+(VJo%<=@>t13yWA}urMlx?bsf6U>C}j?ubsJ+5c4bF?Ach#SLAxGCI>o5OzWXLuR#Ex3ijuF*Z=01gDv z6)y6$d8BIFj;^#GgLBb>gID;-nG(FSjtuYYmEfrRAXk~!@&C^|h@ze!S7&x!@xTr` zO-@m-9~~<%hP&8UM`f&L$JjnL=B|v@?ikz8#_Z-8>p9F`)K{gftkgZth3dYd>yC#w zBI$}@sM@qn;jzs0ux8-7kcGIjx`N~B%=EO9imMv&?CfW<29P%l&m`3J#cbM8Pp1t9 zYY9WWu24qy*^F+)^~80Ba>YtgfdLG#IFy;0Q8YTcR#&uCJXz|;70L>*a&%TrDR?|% zs8e$xfmoA?UD+?4&Kg%^a7bcNQz4#+Yzsz)SPj)kD@06YGy^6i%ksh=N`%@8|LxmMJ7Qdv zvqD$10Ayhh4-n5FVWKiK#>a#S3*!J)#MChp0d33@6;246HENAn)4VwlwM9j$WtuIB zVz%~*v}oe918JK{_3TKR?u(VE6sa-cY8$hd5)l*Ab`!rB#jKHfvsZ0RNztU36txY$ z47(H4^wg}x#7L_NS6g#V5KW^tG|^;^h$ztm_hX;%o0v$zgsN@S9<#Vn)Dg40(GkJi zD`>QH=gO^MX*Bz3`}mnsJH<_*lYA?h;zIH`t^;}MnMEY<_Xu6rMLF*5AS{X{vW^k<-7lS_q~UA{xlf8Y3T``3wbfUUQAzw z)SewacRDt9Iesp3>0*5N;^_-x#8Z}(xSpLf=4KUA2T}#{K9kTA(+cjJ$$(JmxP>yQ zY>)^qW>k&sng~=Ch?6M z{^bkB+UA!>i?#Jj-FLf}2lBNY^FuF>ZVFawuvk;K)O5G$cm4%i(I0&K@aqQ__}_Ro zC1jO;ef}5ce--}bYZ1xy+sI-Ku1oGa@-2C_v3sR)#eT2$-syWsR_h1Wq~k?@>jHnr zbIbGXrWFYPt5a$IOPl|Uj6RYbLl*v{hW0Zj`HxOo0sfA8po-1R!>L{7VFCt9B~md1 zCI$=wwHLbz7zE1+PU9yks%@%RMA}6PT}_Db5$4ptJJwz9CdNRCA4?H&eRl@!#VRTo zBm$JQqHOagobT@-|!x!`TfdD{x!uAH}PrFPZZwd(Dezp(CX z$vXoDXJ^jYIe)e&dJAF`{N8RZwDsrO`U`CXxwe51gnZk{4{P#mXEvl`pYG{dd9KiV zD%X1|zvr0+`f>bCRc1jmR%+40vqZ2z7=CGbDwY~s_d+ow+y%=CNAopFwswXL#n~Mipd>htgIox z^SDVAp?bfow4;eidJ^M~?wA)7pKzC_cCmnNH6Wy67Yn?+CKUu;ZJ=|G32Gf#d0eO$ z6=II+o>_q9IPDnW#$SaH3!oh#mS_ANk!c`3l})GPS)3+T8f5D?T^bA4gSt8k@yKPu z4Kic>)sJ9R;-G;;N-=13&l5)}Fwzn;iV4qVut6Nxl)3mUR;JV&#HA}4fHO%&*E9HL zeF7V5GOd`If*${=n)(?&M45YckA;H7q3Wup8wo9`VCs$upHgutb`viTM=xI(AHgR9 zkEz8V@?=6yW#gq2V5(NQlU7tAF!iUzuIh0`OH9&?puAiupGZvVnRFHs5V#8FZ}3q% ziHZlNHV9M4im7CQBVwrvu}x(lC^SkAjk+34pNsIi0ZGX0H6q51t5`{Zi-H4SBd$TR zQ^H_s{U8}iE8y|m%s&yyJSU_oFw0Ov0q>CBrE2V+pm zpFD7|G6{P};waq$ds>Tfg9x(;So{QCxW-J=*wi?@mQIgY2_hL#@`6n)+KpEdK*-C| z>B&U$8h!z048dPt0=F@bHfvFB<9v8stXb@S^L#<<%86Y?$z2rd-}Eg%`$ixy?koED zuZ*mm$oY>hc-B3Q1y3vd-t}x+1Xq7C&{YWZ=K}rtz|lp=x_3{(8@lfetqiX8ta%6i zV?*B7Vsl_2{DAQvDTtl-#m=JBSD+3xu<8sHX~fx)^K}$_M{~ZTdEZkDXV-lld0$t- z*OT-0ESxQRe0Sz<%`N+0`T5&i-qTiWY*{|NoO(-rU0vbd&{i9J7lj9Mpy;hDwzL*o z0>zg7|F#RR(AN&+t-mvOdu|!_8_Ib?>)!e$`Biy2zUJ*M1_uhkQ@P-&9qaGQ`Sxw{ zsO_0e#I<#=%7F)R&7HB^W2?;v*5n_o%fU6deO(T$?mhJWk$X1^10%VCk-|VYHxSMr z8C~rkTazz7kbMQY^S<1<)-~`!_XjO&^6)>!nsv!_$9dcNTNiMbYQOn<0M!My5$Eb( z_ckoacVR~>lLhbL``*LfZt{RGhq})FBYV-udmZQP{Kwr5=LP<6f)(H-&4A28VHPx8 z2jDfxUn^#-9~_S*V$$tsD-=O+5|uFc@xiZYQo)cu5&)Ns9fXM7ID8?HXk11u3e#L7 zs2XS)i{pfno`_iaNmkJfB2Y@E2s*V4RA@^wTU&}JA;zmp>l9EJ@YksioJSx~lDsG^ zxt3fsad6&pE}n(pYF*m%iL`gqifZ=G8<@sCp%A8LCnDHAhykaGrxb4XrBodhDtQ&G z0ZXfhvpfLV<5bB&wNx<%Rww%ssTox>(?_~x@(2a&xv!j-VH$;D8e*9tZeKEkl|K4q zg=Mg$$=u3hnQ3LJM5odZ12masUubl5U1kN{6>KSDX6C5Oj#~IWoqe`34Joy)cz{;S z2r_e6v3I55TxQX-xd?Sq#17tNjDB#!M2g4hlg8tvN0q9V7iBppX?#MkO==!VOj$yT zsS{=<2-BB+2eHR0J-_rc*sN??IfZY+5Ev(%c|;P%h$-h$nK-|k;Np0{_-+dlUP-#YmE!Gix#&VT4$ z=e>r!|M)6uEY|s#F5SIUs5_9WJ3xevZJw*|T17Qm60$f}9W8lo&z7Z$^KA3T64<2B z)>CYxEzh-YS?pX39qHJl&{h+SEQIo0-Ik@7YoG)5n-to5fukdRd9L|W&c1Lk&-u43 RJl9Go*nIz%09|$y{{y5vyD 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 A=>Px# literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/__pycache__/urls.cpython-313.pyc b/djangoblog-yql(优化后)/__pycache__/urls.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3296621d3fd4e7ebe0a460fc4c5db6d0fb6e6da7 GIT binary patch literal 3149 zcma)8%WoUU86T3%*YYLOvZyy#ew3swEhWcpEu~f<>(Ov&$B0%AQgk6^O%5M6cbAx5 z#x{Wz?kVY|fDZ-iQ+rHqI_8+aAP_+mW)~2GqUfPF2}bYzW_D@ORt#hzjK25x`yMmW z>sX9O@co$nq45`>{!N+TH{lYmfAk{sS0p2XWRL7Ec_c6K3Y7Mhd=f`EMsp><6d(ac z`%6J7L_&-Xl)@5Ecqu|6j1K}IB~eC)N--%;;*1WL64DqMV>Dk%N-2_Jbfk1n8Ykn7 zj+V|#6J&zXu~J%^B$Ltp*z8g>-{R$qkpe!id1*AklKdz*9w;avrIkaXr=UJo)IW14Fdf(Da zG0pV5IYzu@S`PP{pJ{ymzEES%9SC?WZRGPmrJFUprzIhNtFGI0UjaACiN>sRm9 zWR*BnKBkPzxmB;6hgiN5v{&S-XEHlz7v-f8(at$ENIyO+m6un& zOCVl~Ap}$K?n-BEa;`|tAOv%AGTb?92i~8Ym9h*hdVQt7lE0>Y1!J#1RQ0;?pk>sB z`@469O+&9W>m8z6O+)ATy#^M(=#W-hwJc0@^9!NXG%bM`9SfV(!4xb*__B!~o1(B| z5J58t7Mgm^AQ}rHv|Cs;v0!4n#tZN@EURs<6$(|OVv0`kHZdOJiX~PIt$_8yiny{| zu#9%IViu@%0rHy#e*1~4K`?WT-|6TT3eU;QqOOR-Mzt!ay3o|x2C>!zp+*c%(4Lmn zcH0$>*k5z)S5iEnJ6OLqSqzz-c-v0^l~kr`Ct+$bAzNmw|8`?Tj572C;o$ zYID?v_@PVPdDc0$K4M#~<1&o6Tr)a)l@;2Z9npi+m#}Z(Y7j@eFrsZ^qBTtuZcw?3 z^(J-$_-W${-Sh7*fJo)t;67_t!A9LMi$!;Xj63rS)2m^&)e7#0wJNSQq2+~cY)GM#Z3;ETN_>&A`8x<%B=Be&M@8-52Mq}v47nopqlHMP^S$}M<-I}i(0F?bd`v`J-R z7}h8GoE}&0v8_>pWZbRr8>buz;xKTc}{!F4IF=HRgThN@Rvm|S1J{)WD>yljUZ`Ss-w z>WvkcFu9dYU1d-wKi|JL^H`@gfpcel5S8%)hRB-MV0UPDS` zFK(_Wv_NI+&C{`@!6So-a*AJ}iNy9(JM>%4sCHU-oqPn&^dB?xJ2;Ph9*^h58~1Sk zn@667BUCs-SB}uiPw4Uy${Zo_Kj`8ST0BCoLc%m(@Pfnoa81yoXQ{kp_km~bGHZc7f&*YvCAj(C?|f~ zcqMN1#ErvGfB))J+=HKNjcV(j6O{1OJrbU)AL3Hv7L4rwFEgCP literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/__pycache__/utils.cpython-313.pyc b/djangoblog-yql(优化后)/__pycache__/utils.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8fb66587447cc2eaa7066e023cf43d2f908c7ab GIT binary patch literal 11804 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 P`qr2FqpO;{Ye@eAqr 0 + except Exception as e: + logger.error(f"失败邮箱号: {emailto}, {e}") + log.send_result = False + log.save() + + +@receiver(oauth_user_login_signal) +def oauth_user_login_signal_handler(sender, **kwargs): + id = kwargs['id'] + oauthuser = OAuthUser.objects.get(id=id) + site = get_current_site().domain + if oauthuser.picture and not oauthuser.picture.find(site) >= 0: + from djangoblog.utils import save_user_avatar + oauthuser.picture = save_user_avatar(oauthuser.picture) + oauthuser.save() + + delete_sidebar_cache() + + +@receiver(post_save) +def model_post_save_callback( + sender, + instance, + created, + raw, + using, + update_fields, + **kwargs): + clearcache = False + if isinstance(instance, LogEntry): + return + if 'get_full_url' in dir(instance): + is_update_views = update_fields == {'views'} + if not settings.TESTING and not is_update_views: + try: + notify_url = instance.get_full_url() + SpiderNotify.baidu_notify([notify_url]) + except Exception as ex: + logger.error("notify sipder", ex) + if not is_update_views: + clearcache = True + + if isinstance(instance, Comment): + if instance.is_enable: + path = instance.article.get_absolute_url() + site = get_current_site().domain + if site.find(':') > 0: + site = site[0:site.find(':')] + + expire_view_cache( + path, + servername=site, + serverport=80, + key_prefix='blogdetail') + if cache.get('seo_processor'): + cache.delete('seo_processor') + comment_cache_key = 'article_comments_{id}'.format( + id=instance.article.id) + cache.delete(comment_cache_key) + delete_sidebar_cache() + delete_view_cache('article_comments', [str(instance.article.pk)]) + + _thread.start_new_thread(send_comment_email, (instance,)) + + if clearcache: + cache.clear() + + +@receiver(user_logged_in) +@receiver(user_logged_out) +def user_auth_callback(sender, request, user, **kwargs): + if user and user.username: + logger.info(user) + delete_sidebar_cache() + # cache.clear() diff --git a/djangoblog-yql(优化后)/elasticsearch_backend.py b/djangoblog-yql(优化后)/elasticsearch_backend.py new file mode 100644 index 0000000..4afe498 --- /dev/null +++ b/djangoblog-yql(优化后)/elasticsearch_backend.py @@ -0,0 +1,183 @@ +from django.utils.encoding import force_str +from elasticsearch_dsl import Q +from haystack.backends import BaseEngine, BaseSearchBackend, BaseSearchQuery, log_query +from haystack.forms import ModelSearchForm +from haystack.models import SearchResult +from haystack.utils import log as logging + +from blog.documents import ArticleDocument, ArticleDocumentManager +from blog.models import Article + +logger = logging.getLogger(__name__) + + +class ElasticSearchBackend(BaseSearchBackend): + def __init__(self, connection_alias, **connection_options): + super( + ElasticSearchBackend, + self).__init__( + connection_alias, + **connection_options) + self.manager = ArticleDocumentManager() + self.include_spelling = True + + def _get_models(self, iterable): + models = iterable if iterable and iterable[0] else Article.objects.all() + docs = self.manager.convert_to_doc(models) + return docs + + def _create(self, models): + self.manager.create_index() + docs = self._get_models(models) + self.manager.rebuild(docs) + + def _delete(self, models): + for m in models: + m.delete() + return True + + def _rebuild(self, models): + models = models if models else Article.objects.all() + docs = self.manager.convert_to_doc(models) + self.manager.update_docs(docs) + + def update(self, index, iterable, commit=True): + + models = self._get_models(iterable) + self.manager.update_docs(models) + + def remove(self, obj_or_string): + models = self._get_models([obj_or_string]) + self._delete(models) + + def clear(self, models=None, commit=True): + self.remove(None) + + @staticmethod + def get_suggestion(query: str) -> str: + """获取推荐词, 如果没有找到添加原搜索词""" + + search = ArticleDocument.search() \ + .query("match", body=query) \ + .suggest('suggest_search', query, term={'field': 'body'}) \ + .execute() + + keywords = [] + for suggest in search.suggest.suggest_search: + if suggest["options"]: + keywords.append(suggest["options"][0]["text"]) + else: + keywords.append(suggest["text"]) + + return ' '.join(keywords) + + @log_query + def search(self, query_string, **kwargs): + logger.info('search query_string:' + query_string) + + start_offset = kwargs.get('start_offset') + end_offset = kwargs.get('end_offset') + + # 推荐词搜索 + if getattr(self, "is_suggest", None): + suggestion = self.get_suggestion(query_string) + else: + suggestion = query_string + + q = Q('bool', + should=[Q('match', body=suggestion), Q('match', title=suggestion)], + minimum_should_match="70%") + + search = ArticleDocument.search() \ + .query('bool', filter=[q]) \ + .filter('term', status='p') \ + .filter('term', type='a') \ + .source(False)[start_offset: end_offset] + + results = search.execute() + hits = results['hits'].total + raw_results = [] + for raw_result in results['hits']['hits']: + app_label = 'blog' + model_name = 'Article' + additional_fields = {} + + result_class = SearchResult + + result = result_class( + app_label, + model_name, + raw_result['_id'], + raw_result['_score'], + **additional_fields) + raw_results.append(result) + facets = {} + spelling_suggestion = None if query_string == suggestion else suggestion + + return { + 'results': raw_results, + 'hits': hits, + 'facets': facets, + 'spelling_suggestion': spelling_suggestion, + } + + +class ElasticSearchQuery(BaseSearchQuery): + def _convert_datetime(self, date): + if hasattr(date, 'hour'): + return force_str(date.strftime('%Y%m%d%H%M%S')) + else: + return force_str(date.strftime('%Y%m%d000000')) + + def clean(self, query_fragment): + """ + Provides a mechanism for sanitizing user input before presenting the + value to the backend. + + Whoosh 1.X differs here in that you can no longer use a backslash + to escape reserved characters. Instead, the whole word should be + quoted. + """ + words = query_fragment.split() + cleaned_words = [] + + for word in words: + if word in self.backend.RESERVED_WORDS: + word = word.replace(word, word.lower()) + + for char in self.backend.RESERVED_CHARACTERS: + if char in word: + word = "'%s'" % word + break + + cleaned_words.append(word) + + return ' '.join(cleaned_words) + + def build_query_fragment(self, field, filter_type, value): + return value.query_string + + def get_count(self): + results = self.get_results() + return len(results) if results else 0 + + def get_spelling_suggestion(self, preferred_query=None): + return self._spelling_suggestion + + def build_params(self, spelling_query=None): + kwargs = super(ElasticSearchQuery, self).build_params(spelling_query=spelling_query) + return kwargs + + +class ElasticSearchModelSearchForm(ModelSearchForm): + + def search(self): + # 是否建议搜索 + self.searchqueryset.query.backend.is_suggest = self.data.get("is_suggest") != "no" + sqs = super().search() + return sqs + + +class ElasticSearchEngine(BaseEngine): + backend = ElasticSearchBackend + query = ElasticSearchQuery diff --git a/djangoblog-yql(优化后)/feeds.py b/djangoblog-yql(优化后)/feeds.py new file mode 100644 index 0000000..8c4e851 --- /dev/null +++ b/djangoblog-yql(优化后)/feeds.py @@ -0,0 +1,40 @@ +from django.contrib.auth import get_user_model +from django.contrib.syndication.views import Feed +from django.utils import timezone +from django.utils.feedgenerator import Rss201rev2Feed + +from blog.models import Article +from djangoblog.utils import CommonMarkdown + + +class DjangoBlogFeed(Feed): + feed_type = Rss201rev2Feed + + description = '大巧无工,重剑无锋.' + title = "且听风吟 大巧无工,重剑无锋. " + link = "/feed/" + + def author_name(self): + return get_user_model().objects.first().nickname + + def author_link(self): + return get_user_model().objects.first().get_absolute_url() + + def items(self): + return Article.objects.filter(type='a', status='p').order_by('-pub_time')[:5] + + def item_title(self, item): + return item.title + + def item_description(self, item): + return CommonMarkdown.get_markdown(item.body) + + def feed_copyright(self): + now = timezone.now() + return "Copyright© {year} 且听风吟".format(year=now.year) + + def item_link(self, item): + return item.get_absolute_url() + + def item_guid(self, item): + return diff --git a/djangoblog-yql(优化后)/logentryadmin.py b/djangoblog-yql(优化后)/logentryadmin.py new file mode 100644 index 0000000..2f6a535 --- /dev/null +++ b/djangoblog-yql(优化后)/logentryadmin.py @@ -0,0 +1,91 @@ +from django.contrib import admin +from django.contrib.admin.models import DELETION +from django.contrib.contenttypes.models import ContentType +from django.urls import reverse, NoReverseMatch +from django.utils.encoding import force_str +from django.utils.html import escape +from django.utils.safestring import mark_safe +from django.utils.translation import gettext_lazy as _ + + +class LogEntryAdmin(admin.ModelAdmin): + list_filter = [ + 'content_type' + ] + + search_fields = [ + 'object_repr', + 'change_message' + ] + + list_display_links = [ + 'action_time', + 'get_change_message', + ] + list_display = [ + 'action_time', + 'user_link', + 'content_type', + 'object_link', + 'get_change_message', + ] + + def has_add_permission(self, request): + return False + + def has_change_permission(self, request, obj=None): + return ( + request.user.is_superuser or + request.user.has_perm('admin.change_logentry') + ) and request.method != 'POST' + + def has_delete_permission(self, request, obj=None): + return False + + def object_link(self, obj): + object_link = escape(obj.object_repr) + content_type = obj.content_type + + if obj.action_flag != DELETION and content_type is not None: + # try returning an actual link instead of object repr string + try: + url = reverse( + 'admin:{}_{}_change'.format(content_type.app_label, + content_type.model), + args=[obj.object_id] + ) + object_link = '{}'.format(url, object_link) + except NoReverseMatch: + pass + return mark_safe(object_link) + + object_link.admin_order_field = 'object_repr' + object_link.short_description = _('object') + + def user_link(self, obj): + content_type = ContentType.objects.get_for_model(type(obj.user)) + user_link = escape(force_str(obj.user)) + try: + # try returning an actual link instead of object repr string + url = reverse( + 'admin:{}_{}_change'.format(content_type.app_label, + content_type.model), + args=[obj.user.pk] + ) + user_link = '{}'.format(url, user_link) + except NoReverseMatch: + pass + return mark_safe(user_link) + + user_link.admin_order_field = 'user' + user_link.short_description = _('user') + + def get_queryset(self, request): + queryset = super(LogEntryAdmin, self).get_queryset(request) + return queryset.prefetch_related('content_type') + + def get_actions(self, request): + actions = super(LogEntryAdmin, self).get_actions(request) + if 'delete_selected' in actions: + del actions['delete_selected'] + return actions diff --git a/djangoblog-yql(优化后)/plugin_manage/__pycache__/base_plugin.cpython-313.pyc b/djangoblog-yql(优化后)/plugin_manage/__pycache__/base_plugin.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecf7f747b5cd9cb1cdb08ae29ad3d0f41a9f92c3 GIT binary patch literal 1959 zcmah~?N3`(7(chYrS0t-mX|`2ts-G`QA}n~LN=Fe5XH?(dKq8VQ@oo=P9nOd{JFvHmS0U(RcRb*%P^#-_Q?_qzL zfJ-&k&~xUp-`$2J>Okn6y}XTQ%5sST4IrzfUV{-pAa~VD5qd0-p`a-=6)w3MNJy#} z6;(0NJ$&Zu%R?a{bmFzaX9C7zV30o*9vU7QdOcL(jShx+SO)`%w4w&aq(D@fkdsoh zCuk*RF&-z5Dow<@R}*m?JVO)VM#Xqq8pJq-i9=4xsxYbNfVi;~lND9M!ueF{O=XE8 ztRlrH6dL&eIdQ5#G8Rw8A_H%T$yn+nOrK4NbbBPKb97-zm5>mVVoZvRL4pnKJ(F(} zn;_`+1k&(0^*v>#6U->D0%Xtwk9T39(Ab%8?EE5H=sK3~I(A1b91rJ@hjR^l!84Ng zj6Co@nQOmr&x>J2Y%O_P%kMV7K5xt0+V0!hcW7qDE0qHaS|fT@y#f=cD!>wj zDYu69uPHZl)$^6k2_UFtb9w}ha>e<}>#N^sA6(PE{!p7;+{~;#`spK1TVB}sc2%3d zxxRXR^Zhw(=Ck7RSH;D<#oO89wd>l-=Np%9ZCt#otz6l-@?Pa|@#DGmAFpy#t^f_0 zEXL(2NO~w}CUp?`n1l%{Cnr+a28OX4pp+(DPuDb*q`4}_RcZFpy$1j?=x+|$J@bx> zjs>;gJCyew$~AZ2aOE0bxNmzAH^7!%p`&5cLq}tnMesP7(lm-(@%9aEX13(~=H(^u z_kVmY9jN$hoCz)Mb%eGSX{~Z(cZs%wSg`_R&=&aO+I#6rzG-1)X}7|+mVmp@`?!Dh zd8WtQ2|b-Y3R<{Fm%i8L7fY_M|NLd~ots=gmee#(_6M}tX>H*fqb8=`EoN^O=T>Nn zmp{>_?{JVwHYp|~;)qJhIF=_>Ih7>VwinDF_$RV%(5;1YttPiW-Nq zw%cNH{o}S<3>WCZpoLgz)5ysfu|sIi=naIQ0ugSapqtojme`J#Jbek%p9C#_r2}Bg k%rML!$oU$Fasv->~oyJzpr)csrcG{bEp0R8I!0k+%!DF6Tf literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/plugin_manage/__pycache__/hook_constants.cpython-313.pyc b/djangoblog-yql(优化后)/plugin_manage/__pycache__/hook_constants.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..981f0b4468dff5878eb0a7a9e0cce8b41b06f61e GIT binary patch literal 387 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 +
+
文章目录
+ +
+ + \ No newline at end of file diff --git a/djangoblog-yql(优化后)/settings.py b/djangoblog-yql(优化后)/settings.py new file mode 100644 index 0000000..d0445a4 --- /dev/null +++ b/djangoblog-yql(优化后)/settings.py @@ -0,0 +1,344 @@ +""" +Django settings for djangoblog project. + +Generated by 'django-admin startproject' using Django 1.10.2. + +For more information on this file, see +https://docs.djangoproject.com/en/1.10/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.10/ref/settings/ +""" +import os +import sys +from pathlib import Path + +from django.utils.translation import gettext_lazy as _ + + +def env_to_bool(env, default): + str_val = os.environ.get(env) + return default if str_val is None else str_val == 'True' + + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = os.environ.get( + 'DJANGO_SECRET_KEY') or 'n9ceqv38)#&mwuat@(mjb_p%em$e8$qyr#fw9ot!=ba6lijx-6' +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = env_to_bool('DJANGO_DEBUG', True) +# DEBUG = False +TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test' + +# ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*', '127.0.0.1', 'example.com'] +# django 4.0新增配置 +CSRF_TRUSTED_ORIGINS = ['http://example.com'] +# Application definition + + +INSTALLED_APPS = [ + # 'django.contrib.admin', + 'django.contrib.admin.apps.SimpleAdminConfig', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.sites', + 'django.contrib.sitemaps', + 'mdeditor', + 'haystack', + 'blog', + 'accounts', + 'comments', + 'oauth', + 'servermanager', + 'owntracks', + 'compressor', + 'djangoblog' +] + +MIDDLEWARE = [ + + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.gzip.GZipMiddleware', + # 'django.middleware.cache.UpdateCacheMiddleware', + 'django.middleware.common.CommonMiddleware', + # 'django.middleware.cache.FetchFromCacheMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.http.ConditionalGetMiddleware', + 'blog.middleware.OnlineMiddleware' +] + +ROOT_URLCONF = 'djangoblog.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, 'templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'blog.context_processors.seo_processor' + ], + }, + }, +] + +WSGI_APPLICATION = 'djangoblog.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/1.10/ref/settings/#databases + + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': os.environ.get('DJANGO_MYSQL_DATABASE') or 'djangoblog', + 'USER': os.environ.get('DJANGO_MYSQL_USER') or 'root', + 'PASSWORD': os.environ.get('DJANGO_MYSQL_PASSWORD') or 'yql041128', + 'HOST': os.environ.get('DJANGO_MYSQL_HOST') or '127.0.0.1', + 'PORT': int( + os.environ.get('DJANGO_MYSQL_PORT') or 3306), + 'OPTIONS': { + 'charset': 'utf8mb4'}, + }} + +# Password validation +# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +LANGUAGES = ( + ('en', _('English')), + ('zh-hans', _('Simplified Chinese')), + ('zh-hant', _('Traditional Chinese')), +) +LOCALE_PATHS = ( + os.path.join(BASE_DIR, 'locale'), +) + +LANGUAGE_CODE = 'zh-hans' + +TIME_ZONE = 'Asia/Shanghai' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = False + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.10/howto/static-files/ + + +HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'djangoblog.whoosh_cn_backend.WhooshEngine', + 'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'), + }, +} +# Automatically update searching index +HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' +# Allow user login with username and password +AUTHENTICATION_BACKENDS = [ + 'accounts.user_login_backend.EmailOrUsernameModelBackend'] + +STATIC_ROOT = os.path.join(BASE_DIR, 'collectedstatic') + +STATIC_URL = '/static/' +STATICFILES = os.path.join(BASE_DIR, 'static') + +AUTH_USER_MODEL = 'accounts.BlogUser' +LOGIN_URL = '/login/' + +TIME_FORMAT = '%Y-%m-%d %H:%M:%S' +DATE_TIME_FORMAT = '%Y-%m-%d' + +# bootstrap color styles +BOOTSTRAP_COLOR_TYPES = [ + 'default', 'primary', 'success', 'info', 'warning', 'danger' +] + +# paginate +PAGINATE_BY = 10 +# http cache timeout +CACHE_CONTROL_MAX_AGE = 2592000 +# cache setting +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + 'TIMEOUT': 10800, + 'LOCATION': 'unique-snowflake', + } +} +# 使用redis作为缓存 +if os.environ.get("DJANGO_REDIS_URL"): + CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.redis.RedisCache', + 'LOCATION': f'redis://{os.environ.get("DJANGO_REDIS_URL")}', + } + } + +SITE_ID = 1 +BAIDU_NOTIFY_URL = os.environ.get('DJANGO_BAIDU_NOTIFY_URL') \ + or 'http://data.zz.baidu.com/urls?site=https://www.lylinux.net&token=1uAOGrMsUm5syDGn' + +# Email: +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_USE_TLS = env_to_bool('DJANGO_EMAIL_TLS', False) +EMAIL_USE_SSL = env_to_bool('DJANGO_EMAIL_SSL', True) +EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST') or 'smtp.mxhichina.com' +EMAIL_PORT = int(os.environ.get('DJANGO_EMAIL_PORT') or 465) +EMAIL_HOST_USER = os.environ.get('DJANGO_EMAIL_USER') +EMAIL_HOST_PASSWORD = os.environ.get('DJANGO_EMAIL_PASSWORD') +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER +SERVER_EMAIL = EMAIL_HOST_USER +# Setting debug=false did NOT handle except email notifications +ADMINS = [('admin', os.environ.get('DJANGO_ADMIN_EMAIL') or 'admin@admin.com')] +# WX ADMIN password(Two times md5) +WXADMIN = os.environ.get( + 'DJANGO_WXADMIN_PASSWORD') or '995F03AC401D6CABABAEF756FC4D43C7' + +LOG_PATH = os.path.join(BASE_DIR, 'logs') +if not os.path.exists(LOG_PATH): + os.makedirs(LOG_PATH, exist_ok=True) + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'root': { + 'level': 'INFO', + 'handlers': ['console', 'log_file'], + }, + 'formatters': { + 'verbose': { + 'format': '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d %(module)s] %(message)s', + } + }, + 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, + 'require_debug_true': { + '()': 'django.utils.log.RequireDebugTrue', + }, + }, + 'handlers': { + 'log_file': { + 'level': 'INFO', + 'class': 'logging.handlers.TimedRotatingFileHandler', + 'filename': os.path.join(LOG_PATH, 'djangoblog.log'), + 'when': 'D', + 'formatter': 'verbose', + 'interval': 1, + 'delay': True, + 'backupCount': 5, + 'encoding': 'utf-8' + }, + 'console': { + 'level': 'DEBUG', + 'filters': ['require_debug_true'], + 'class': 'logging.StreamHandler', + 'formatter': 'verbose' + }, + 'null': { + 'class': 'logging.NullHandler', + }, + 'mail_admins': { + 'level': 'ERROR', + 'filters': ['require_debug_false'], + 'class': 'django.utils.log.AdminEmailHandler' + } + }, + 'loggers': { + 'djangoblog': { + 'handlers': ['log_file', 'console'], + 'level': 'INFO', + 'propagate': True, + }, + 'django.request': { + 'handlers': ['mail_admins'], + 'level': 'ERROR', + 'propagate': False, + } + } +} + +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', + # other + 'compressor.finders.CompressorFinder', +) +COMPRESS_ENABLED = True +# COMPRESS_OFFLINE = True + + +COMPRESS_CSS_FILTERS = [ + # creates absolute urls from relative ones + 'compressor.filters.css_default.CssAbsoluteFilter', + # css minimizer + 'compressor.filters.cssmin.CSSMinFilter' +] +COMPRESS_JS_FILTERS = [ + 'compressor.filters.jsmin.JSMinFilter' +] + +MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads') +MEDIA_URL = '/media/' +X_FRAME_OPTIONS = 'SAMEORIGIN' + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +if os.environ.get('DJANGO_ELASTICSEARCH_HOST'): + ELASTICSEARCH_DSL = { + 'default': { + 'hosts': os.environ.get('DJANGO_ELASTICSEARCH_HOST') + }, + } + HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'djangoblog.elasticsearch_backend.ElasticSearchEngine', + }, + } + +# Plugin System +PLUGINS_DIR = BASE_DIR / 'plugins' +ACTIVE_PLUGINS = [ + 'article_copyright', + 'reading_time', + 'external_links', + 'view_count', + 'seo_optimizer', + 'reading_time', # 确保这行存在 +] \ No newline at end of file diff --git a/djangoblog-yql(优化后)/sitemap.py b/djangoblog-yql(优化后)/sitemap.py new file mode 100644 index 0000000..8b7d446 --- /dev/null +++ b/djangoblog-yql(优化后)/sitemap.py @@ -0,0 +1,59 @@ +from django.contrib.sitemaps import Sitemap +from django.urls import reverse + +from blog.models import Article, Category, Tag + + +class StaticViewSitemap(Sitemap): + priority = 0.5 + changefreq = 'daily' + + def items(self): + return ['blog:index', ] + + def location(self, item): + return reverse(item) + + +class ArticleSiteMap(Sitemap): + changefreq = "monthly" + priority = "0.6" + + def items(self): + return Article.objects.filter(status='p') + + def lastmod(self, obj): + return obj.last_modify_time + + +class CategorySiteMap(Sitemap): + changefreq = "Weekly" + priority = "0.6" + + def items(self): + return Category.objects.all() + + def lastmod(self, obj): + return obj.last_modify_time + + +class TagSiteMap(Sitemap): + changefreq = "Weekly" + priority = "0.3" + + def items(self): + return Tag.objects.all() + + def lastmod(self, obj): + return obj.last_modify_time + + +class UserSiteMap(Sitemap): + changefreq = "Weekly" + priority = "0.3" + + def items(self): + return list(set(map(lambda x: x.author, Article.objects.all()))) + + def lastmod(self, obj): + return obj.date_joined diff --git a/djangoblog-yql(优化后)/spider_notify.py b/djangoblog-yql(优化后)/spider_notify.py new file mode 100644 index 0000000..7b909e9 --- /dev/null +++ b/djangoblog-yql(优化后)/spider_notify.py @@ -0,0 +1,21 @@ +import logging + +import requests +from django.conf import settings + +logger = logging.getLogger(__name__) + + +class SpiderNotify(): + @staticmethod + def baidu_notify(urls): + try: + data = '\n'.join(urls) + result = requests.post(settings.BAIDU_NOTIFY_URL, data=data) + logger.info(result.text) + except Exception as e: + logger.error(e) + + @staticmethod + def notify(url): + SpiderNotify.baidu_notify(url) diff --git a/djangoblog-yql(优化后)/tests.py b/djangoblog-yql(优化后)/tests.py new file mode 100644 index 0000000..01237d9 --- /dev/null +++ b/djangoblog-yql(优化后)/tests.py @@ -0,0 +1,32 @@ +from django.test import TestCase + +from djangoblog.utils import * + + +class DjangoBlogTest(TestCase): + def setUp(self): + pass + + def test_utils(self): + md5 = get_sha256('test') + self.assertIsNotNone(md5) + c = CommonMarkdown.get_markdown(''' + # Title1 + + ```python + import os + ``` + + [url](https://www.lylinux.net/) + + [ddd](http://www.baidu.com) + + + ''') + self.assertIsNotNone(c) + d = { + 'd': 'key1', + 'd2': 'key2' + } + data = parse_dict_to_url(d) + self.assertIsNotNone(data) diff --git a/djangoblog-yql(优化后)/urls.py b/djangoblog-yql(优化后)/urls.py new file mode 100644 index 0000000..4aae58a --- /dev/null +++ b/djangoblog-yql(优化后)/urls.py @@ -0,0 +1,64 @@ +"""djangoblog URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.10/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf import settings +from django.conf.urls.i18n import i18n_patterns +from django.conf.urls.static import static +from django.contrib.sitemaps.views import sitemap +from django.urls import path, include +from django.urls import re_path +from haystack.views import search_view_factory + +from blog.views import EsSearchView +from djangoblog.admin_site import admin_site +from djangoblog.elasticsearch_backend import ElasticSearchModelSearchForm +from djangoblog.feeds import DjangoBlogFeed +from djangoblog.sitemap import ArticleSiteMap, CategorySiteMap, StaticViewSitemap, TagSiteMap, UserSiteMap + +sitemaps = { + + 'blog': ArticleSiteMap, + 'Category': CategorySiteMap, + 'Tag': TagSiteMap, + 'User': UserSiteMap, + 'static': StaticViewSitemap +} + +handler404 = 'blog.views.page_not_found_view' +handler500 = 'blog.views.server_error_view' +handle403 = 'blog.views.permission_denied_view' + +urlpatterns = [ + path('i18n/', include('django.conf.urls.i18n')), +] +urlpatterns += i18n_patterns( + re_path(r'^admin/', admin_site.urls), + re_path(r'', include('blog.urls', namespace='blog')), + re_path(r'mdeditor/', include('mdeditor.urls')), + re_path(r'', include('comments.urls', namespace='comment')), + re_path(r'', include('accounts.urls', namespace='account')), + re_path(r'', include('oauth.urls', namespace='oauth')), + re_path(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, + name='django.contrib.sitemaps.views.sitemap'), + re_path(r'^feed/$', DjangoBlogFeed()), + re_path(r'^rss/$', DjangoBlogFeed()), + re_path('^search', search_view_factory(view_class=EsSearchView, form_class=ElasticSearchModelSearchForm), + name='search'), + re_path(r'', include('servermanager.urls', namespace='servermanager')), + re_path(r'', include('owntracks.urls', namespace='owntracks')) + , prefix_default_language=False) + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +if settings.DEBUG: + urlpatterns += static(settings.MEDIA_URL, + document_root=settings.MEDIA_ROOT) diff --git a/djangoblog-yql(优化后)/utils.py b/djangoblog-yql(优化后)/utils.py new file mode 100644 index 0000000..e7de185 --- /dev/null +++ b/djangoblog-yql(优化后)/utils.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +import logging +import os +import random +import string +import uuid +from hashlib import sha256 + +import bleach +import markdown +import requests +from django.conf import settings +from django.contrib.sites.models import Site +from django.core.cache import cache +from django.templatetags.static import static +from .plugin_manage.hooks import apply_filters # 新增导入 +logger = logging.getLogger(__name__) + + +def get_max_articleid_commentid(): + from blog.models import Article + from comments.models import Comment + return (Article.objects.latest().pk, Comment.objects.latest().pk) + + +def get_sha256(str): + m = sha256(str.encode('utf-8')) + return m.hexdigest() + + +def cache_decorator(expiration=3 * 60): + def wrapper(func): + def news(*args, **kwargs): + try: + view = args[0] + key = view.get_cache_key() + except: + key = None + if not key: + unique_str = repr((func, args, kwargs)) + + m = sha256(unique_str.encode('utf-8')) + key = m.hexdigest() + value = cache.get(key) + if value is not None: + # logger.info('cache_decorator get cache:%s key:%s' % (func.__name__, key)) + if str(value) == '__default_cache_value__': + return None + else: + return value + else: + logger.debug( + 'cache_decorator set cache:%s key:%s' % + (func.__name__, key)) + value = func(*args, **kwargs) + if value is None: + cache.set(key, '__default_cache_value__', expiration) + else: + cache.set(key, value, expiration) + return value + + return news + + return wrapper + + +def expire_view_cache(path, servername, serverport, key_prefix=None): + ''' + 刷新视图缓存 + :param path:url路径 + :param servername:host + :param serverport:端口 + :param key_prefix:前缀 + :return:是否成功 + ''' + from django.http import HttpRequest + from django.utils.cache import get_cache_key + + request = HttpRequest() + request.META = {'SERVER_NAME': servername, 'SERVER_PORT': serverport} + request.path = path + + key = get_cache_key(request, key_prefix=key_prefix, cache=cache) + if key: + logger.info('expire_view_cache:get key:{path}'.format(path=path)) + if cache.get(key): + cache.delete(key) + return True + return False + + +@cache_decorator() +def get_current_site(): + site = Site.objects.get_current() + return site + + +class CommonMarkdown: + @staticmethod + def _convert_markdown(value): + # 转换Markdown为HTML + md = markdown.Markdown( + extensions=[ + 'extra', + 'codehilite', + 'toc', + 'tables', + ] + ) + body = md.convert(value) + toc = md.toc + + # 应用文章渲染后钩子(新增) + body = apply_filters('after_article_render', body) + + return body, toc + + @staticmethod + def get_markdown_with_toc(value): + body, toc = CommonMarkdown._convert_markdown(value) + return body, toc + + @staticmethod + def get_markdown(value): + body, toc = CommonMarkdown._convert_markdown(value) + return body + + +def send_email(emailto, title, content): + from djangoblog.blog_signals import send_email_signal + send_email_signal.send( + send_email.__class__, + emailto=emailto, + title=title, + content=content) + + +def generate_code() -> str: + """生成随机数验证码""" + return ''.join(random.sample(string.digits, 6)) + + +def parse_dict_to_url(dict): + from urllib.parse import quote + url = '&'.join(['{}={}'.format(quote(k, safe='/'), quote(v, safe='/')) + for k, v in dict.items()]) + return url + + +def get_blog_setting(): + value = cache.get('get_blog_setting') + if value: + return value + else: + from blog.models import BlogSettings + if not BlogSettings.objects.count(): + setting = BlogSettings() + setting.site_name = 'djangoblog' + setting.site_description = '基于Django的博客系统' + setting.site_seo_description = '基于Django的博客系统' + setting.site_keywords = 'Django,Python' + setting.article_sub_length = 300 + setting.sidebar_article_count = 10 + setting.sidebar_comment_count = 5 + setting.show_google_adsense = False + setting.open_site_comment = True + setting.analytics_code = '' + setting.beian_code = '' + setting.show_gongan_code = False + setting.comment_need_review = False + setting.save() + value = BlogSettings.objects.first() + logger.info('set cache get_blog_setting') + cache.set('get_blog_setting', value) + return value + + +def save_user_avatar(url): + ''' + 保存用户头像 + :param url:头像url + :return: 本地路径 + ''' + logger.info(url) + + try: + basedir = os.path.join(settings.STATICFILES, 'avatar') + rsp = requests.get(url, timeout=2) + if rsp.status_code == 200: + if not os.path.exists(basedir): + os.makedirs(basedir) + + image_extensions = ['.jpg', '.png', 'jpeg', '.gif'] + isimage = len([i for i in image_extensions if url.endswith(i)]) > 0 + ext = os.path.splitext(url)[1] if isimage else '.jpg' + save_filename = str(uuid.uuid4().hex) + ext + logger.info('保存用户头像:' + basedir + save_filename) + with open(os.path.join(basedir, save_filename), 'wb+') as file: + file.write(rsp.content) + return static('avatar/' + save_filename) + except Exception as e: + logger.error(e) + return static('blog/img/avatar.png') + + +def delete_sidebar_cache(): + from blog.models import LinkShowType + keys = ["sidebar" + x for x in LinkShowType.values] + for k in keys: + logger.info('delete sidebar key:' + k) + cache.delete(k) + + +def delete_view_cache(prefix, keys): + from django.core.cache.utils import make_template_fragment_key + key = make_template_fragment_key(prefix, keys) + cache.delete(key) + + +def get_resource_url(): + if settings.STATIC_URL: + return settings.STATIC_URL + else: + site = get_current_site() + return 'http://' + site.domain + '/static/' + + +ALLOWED_TAGS = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul', 'h1', + 'h2', 'p'] +ALLOWED_ATTRIBUTES = {'a': ['href', 'title'], 'abbr': ['title'], 'acronym': ['title']} + + +def sanitize_html(html): + return bleach.clean(html, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRIBUTES) + +# 在djangoblog/utils.py中添加 +def estimate_reading_time(content: str) -> int: + """估算 估算文章阅读时长(按每分钟300字计算) + 返回分钟数,最少1分钟 + """ + # 简单清洗HTML标签,只保留文本内容 + import re + clean_text = re.sub(r'<.*?>', '', content) + # 计算中文字符数(近似-zA-Z视为0.5个汉字) + char_count = 0 + for c in clean_text: + if '\u4e00' <= c <= '\u9fff': # 中文字符 + char_count += 1 + elif c.isalpha(): # 字母 + char_count += 0.5 + # 计算时长 + minutes = int(char_count / 300) + return max(minutes, 1) # 最少1分钟 \ No newline at end of file diff --git a/djangoblog-yql(优化后)/whoosh_cn_backend.py b/djangoblog-yql(优化后)/whoosh_cn_backend.py new file mode 100644 index 0000000..b5e6f6f --- /dev/null +++ b/djangoblog-yql(优化后)/whoosh_cn_backend.py @@ -0,0 +1,1045 @@ +# encoding: utf-8 + +from __future__ import absolute_import, division, print_function, unicode_literals + +import json +import os +import re +import shutil +import threading +import warnings + +import six +from django.conf import settings +from django.core.exceptions import ImproperlyConfigured +from datetime import datetime +from django.utils.encoding import force_str +from haystack.backends import BaseEngine, BaseSearchBackend, BaseSearchQuery, EmptyResults, log_query +from haystack.constants import DJANGO_CT, DJANGO_ID, ID +from haystack.exceptions import MissingDependency, SearchBackendError, SkipDocument +from haystack.inputs import Clean, Exact, PythonData, Raw +from haystack.models import SearchResult +from haystack.utils import get_identifier, get_model_ct +from haystack.utils import log as logging +from haystack.utils.app_loading import haystack_get_model +from jieba.analyse import ChineseAnalyzer +from whoosh import index +from whoosh.analysis import StemmingAnalyzer +from whoosh.fields import BOOLEAN, DATETIME, IDLIST, KEYWORD, NGRAM, NGRAMWORDS, NUMERIC, Schema, TEXT +from whoosh.fields import ID as WHOOSH_ID +from whoosh.filedb.filestore import FileStorage, RamStorage +from whoosh.highlight import ContextFragmenter, HtmlFormatter +from whoosh.highlight import highlight as whoosh_highlight +from whoosh.qparser import QueryParser +from whoosh.searching import ResultsPage +from whoosh.writing import AsyncWriter + +try: + import whoosh +except ImportError: + raise MissingDependency( + "The 'whoosh' backend requires the installation of 'Whoosh'. Please refer to the documentation.") + +# Handle minimum requirement. +if not hasattr(whoosh, '__version__') or whoosh.__version__ < (2, 5, 0): + raise MissingDependency( + "The 'whoosh' backend requires version 2.5.0 or greater.") + +# Bubble up the correct error. + +DATETIME_REGEX = re.compile( + '^(?P\d{4})-(?P\d{2})-(?P\d{2})T(?P\d{2}):(?P\d{2}):(?P\d{2})(\.\d{3,6}Z?)?$') +LOCALS = threading.local() +LOCALS.RAM_STORE = None + + +class WhooshHtmlFormatter(HtmlFormatter): + """ + This is a HtmlFormatter simpler than the whoosh.HtmlFormatter. + We use it to have consistent results across backends. Specifically, + Solr, Xapian and Elasticsearch are using this formatting. + """ + template = '<%(tag)s>%(t)s' + + +class WhooshSearchBackend(BaseSearchBackend): + # Word reserved by Whoosh for special use. + RESERVED_WORDS = ( + 'AND', + 'NOT', + 'OR', + 'TO', + ) + + # Characters reserved by Whoosh for special use. + # The '\\' must come first, so as not to overwrite the other slash + # replacements. + RESERVED_CHARACTERS = ( + '\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', + '[', ']', '^', '"', '~', '*', '?', ':', '.', + ) + + def __init__(self, connection_alias, **connection_options): + super( + WhooshSearchBackend, + self).__init__( + connection_alias, + **connection_options) + self.setup_complete = False + self.use_file_storage = True + self.post_limit = getattr( + connection_options, + 'POST_LIMIT', + 128 * 1024 * 1024) + self.path = connection_options.get('PATH') + + if connection_options.get('STORAGE', 'file') != 'file': + self.use_file_storage = False + + if self.use_file_storage and not self.path: + raise ImproperlyConfigured( + "You must specify a 'PATH' in your settings for connection '%s'." % + connection_alias) + + self.log = logging.getLogger('haystack') + + def setup(self): + """ + Defers loading until needed. + """ + from haystack import connections + new_index = False + + # Make sure the index is there. + if self.use_file_storage and not os.path.exists(self.path): + os.makedirs(self.path) + new_index = True + + if self.use_file_storage and not os.access(self.path, os.W_OK): + raise IOError( + "The path to your Whoosh index '%s' is not writable for the current user/group." % + self.path) + + if self.use_file_storage: + self.storage = FileStorage(self.path) + else: + global LOCALS + + if getattr(LOCALS, 'RAM_STORE', None) is None: + LOCALS.RAM_STORE = RamStorage() + + self.storage = LOCALS.RAM_STORE + + self.content_field_name, self.schema = self.build_schema( + connections[self.connection_alias].get_unified_index().all_searchfields()) + self.parser = QueryParser(self.content_field_name, schema=self.schema) + + if new_index is True: + self.index = self.storage.create_index(self.schema) + else: + try: + self.index = self.storage.open_index(schema=self.schema) + except index.EmptyIndexError: + self.index = self.storage.create_index(self.schema) + + self.setup_complete = True + + def build_schema(self, fields): + schema_fields = { + ID: WHOOSH_ID(stored=True, unique=True), + DJANGO_CT: WHOOSH_ID(stored=True), + DJANGO_ID: WHOOSH_ID(stored=True), + } + # Grab the number of keys that are hard-coded into Haystack. + # We'll use this to (possibly) fail slightly more gracefully later. + initial_key_count = len(schema_fields) + content_field_name = '' + + for field_name, field_class in fields.items(): + if field_class.is_multivalued: + if field_class.indexed is False: + schema_fields[field_class.index_fieldname] = IDLIST( + stored=True, field_boost=field_class.boost) + else: + schema_fields[field_class.index_fieldname] = KEYWORD( + stored=True, commas=True, scorable=True, field_boost=field_class.boost) + elif field_class.field_type in ['date', 'datetime']: + schema_fields[field_class.index_fieldname] = DATETIME( + stored=field_class.stored, sortable=True) + elif field_class.field_type == 'integer': + schema_fields[field_class.index_fieldname] = NUMERIC( + stored=field_class.stored, numtype=int, field_boost=field_class.boost) + elif field_class.field_type == 'float': + schema_fields[field_class.index_fieldname] = NUMERIC( + stored=field_class.stored, numtype=float, field_boost=field_class.boost) + elif field_class.field_type == 'boolean': + # Field boost isn't supported on BOOLEAN as of 1.8.2. + schema_fields[field_class.index_fieldname] = BOOLEAN( + stored=field_class.stored) + elif field_class.field_type == 'ngram': + schema_fields[field_class.index_fieldname] = NGRAM( + minsize=3, maxsize=15, stored=field_class.stored, field_boost=field_class.boost) + elif field_class.field_type == 'edge_ngram': + schema_fields[field_class.index_fieldname] = NGRAMWORDS(minsize=2, maxsize=15, at='start', + stored=field_class.stored, + field_boost=field_class.boost) + else: + # schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True) + schema_fields[field_class.index_fieldname] = TEXT( + stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True) + if field_class.document is True: + content_field_name = field_class.index_fieldname + schema_fields[field_class.index_fieldname].spelling = True + + # Fail more gracefully than relying on the backend to die if no fields + # are found. + if len(schema_fields) <= initial_key_count: + raise SearchBackendError( + "No fields were found in any search_indexes. Please correct this before attempting to search.") + + return (content_field_name, Schema(**schema_fields)) + + def update(self, index, iterable, commit=True): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + writer = AsyncWriter(self.index) + + for obj in iterable: + try: + doc = index.full_prepare(obj) + except SkipDocument: + self.log.debug(u"Indexing for object `%s` skipped", obj) + else: + # Really make sure it's unicode, because Whoosh won't have it any + # other way. + for key in doc: + doc[key] = self._from_python(doc[key]) + + # Document boosts aren't supported in Whoosh 2.5.0+. + if 'boost' in doc: + del doc['boost'] + + try: + writer.update_document(**doc) + except Exception as e: + if not self.silently_fail: + raise + + # We'll log the object identifier but won't include the actual object + # to avoid the possibility of that generating encoding errors while + # processing the log message: + self.log.error( + u"%s while preparing object for update" % + e.__class__.__name__, + exc_info=True, + extra={ + "data": { + "index": index, + "object": get_identifier(obj)}}) + + if len(iterable) > 0: + # For now, commit no matter what, as we run into locking issues + # otherwise. + writer.commit() + + def remove(self, obj_or_string, commit=True): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + whoosh_id = get_identifier(obj_or_string) + + try: + self.index.delete_by_query( + q=self.parser.parse( + u'%s:"%s"' % + (ID, whoosh_id))) + except Exception as e: + if not self.silently_fail: + raise + + self.log.error( + "Failed to remove document '%s' from Whoosh: %s", + whoosh_id, + e, + exc_info=True) + + def clear(self, models=None, commit=True): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + + if models is not None: + assert isinstance(models, (list, tuple)) + + try: + if models is None: + self.delete_index() + else: + models_to_delete = [] + + for model in models: + models_to_delete.append( + u"%s:%s" % + (DJANGO_CT, get_model_ct(model))) + + self.index.delete_by_query( + q=self.parser.parse( + u" OR ".join(models_to_delete))) + except Exception as e: + if not self.silently_fail: + raise + + if models is not None: + self.log.error( + "Failed to clear Whoosh index of models '%s': %s", + ','.join(models_to_delete), + e, + exc_info=True) + else: + self.log.error( + "Failed to clear Whoosh index: %s", e, exc_info=True) + + def delete_index(self): + # Per the Whoosh mailing list, if wiping out everything from the index, + # it's much more efficient to simply delete the index files. + if self.use_file_storage and os.path.exists(self.path): + shutil.rmtree(self.path) + elif not self.use_file_storage: + self.storage.clean() + + # Recreate everything. + self.setup() + + def optimize(self): + if not self.setup_complete: + self.setup() + + self.index = self.index.refresh() + self.index.optimize() + + def calculate_page(self, start_offset=0, end_offset=None): + # Prevent against Whoosh throwing an error. Requires an end_offset + # greater than 0. + if end_offset is not None and end_offset <= 0: + end_offset = 1 + + # Determine the page. + page_num = 0 + + if end_offset is None: + end_offset = 1000000 + + if start_offset is None: + start_offset = 0 + + page_length = end_offset - start_offset + + if page_length and page_length > 0: + page_num = int(start_offset / page_length) + + # Increment because Whoosh uses 1-based page numbers. + page_num += 1 + return page_num, page_length + + @log_query + def search( + self, + query_string, + sort_by=None, + start_offset=0, + end_offset=None, + fields='', + highlight=False, + facets=None, + date_facets=None, + query_facets=None, + narrow_queries=None, + spelling_query=None, + within=None, + dwithin=None, + distance_point=None, + models=None, + limit_to_registered_models=None, + result_class=None, + **kwargs): + if not self.setup_complete: + self.setup() + + # A zero length query should return no results. + if len(query_string) == 0: + return { + 'results': [], + 'hits': 0, + } + + query_string = force_str(query_string) + + # A one-character query (non-wildcard) gets nabbed by a stopwords + # filter and should yield zero results. + if len(query_string) <= 1 and query_string != u'*': + return { + 'results': [], + 'hits': 0, + } + + reverse = False + + if sort_by is not None: + # Determine if we need to reverse the results and if Whoosh can + # handle what it's being asked to sort by. Reversing is an + # all-or-nothing action, unfortunately. + sort_by_list = [] + reverse_counter = 0 + + for order_by in sort_by: + if order_by.startswith('-'): + reverse_counter += 1 + + if reverse_counter and reverse_counter != len(sort_by): + raise SearchBackendError("Whoosh requires all order_by fields" + " to use the same sort direction") + + for order_by in sort_by: + if order_by.startswith('-'): + sort_by_list.append(order_by[1:]) + + if len(sort_by_list) == 1: + reverse = True + else: + sort_by_list.append(order_by) + + if len(sort_by_list) == 1: + reverse = False + + sort_by = sort_by_list[0] + + if facets is not None: + warnings.warn( + "Whoosh does not handle faceting.", + Warning, + stacklevel=2) + + if date_facets is not None: + warnings.warn( + "Whoosh does not handle date faceting.", + Warning, + stacklevel=2) + + if query_facets is not None: + warnings.warn( + "Whoosh does not handle query faceting.", + Warning, + stacklevel=2) + + narrowed_results = None + self.index = self.index.refresh() + + if limit_to_registered_models is None: + limit_to_registered_models = getattr( + settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True) + + if models and len(models): + model_choices = sorted(get_model_ct(model) for model in models) + elif limit_to_registered_models: + # Using narrow queries, limit the results to only models handled + # with the current routers. + model_choices = self.build_models_list() + else: + model_choices = [] + + if len(model_choices) > 0: + if narrow_queries is None: + narrow_queries = set() + + narrow_queries.add(' OR '.join( + ['%s:%s' % (DJANGO_CT, rm) for rm in model_choices])) + + narrow_searcher = None + + if narrow_queries is not None: + # Potentially expensive? I don't see another way to do it in + # Whoosh... + narrow_searcher = self.index.searcher() + + for nq in narrow_queries: + recent_narrowed_results = narrow_searcher.search( + self.parser.parse(force_str(nq)), limit=None) + + if len(recent_narrowed_results) <= 0: + return { + 'results': [], + 'hits': 0, + } + + if narrowed_results: + narrowed_results.filter(recent_narrowed_results) + else: + narrowed_results = recent_narrowed_results + + self.index = self.index.refresh() + + if self.index.doc_count(): + searcher = self.index.searcher() + parsed_query = self.parser.parse(query_string) + + # In the event of an invalid/stopworded query, recover gracefully. + if parsed_query is None: + return { + 'results': [], + 'hits': 0, + } + + page_num, page_length = self.calculate_page( + start_offset, end_offset) + + search_kwargs = { + 'pagelen': page_length, + 'sortedby': sort_by, + 'reverse': reverse, + } + + # Handle the case where the results have been narrowed. + if narrowed_results is not None: + search_kwargs['filter'] = narrowed_results + + try: + raw_page = searcher.search_page( + parsed_query, + page_num, + **search_kwargs + ) + except ValueError: + if not self.silently_fail: + raise + + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + # Because as of Whoosh 2.5.1, it will return the wrong page of + # results if you request something too high. :( + if raw_page.pagenum < page_num: + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + results = self._process_results( + raw_page, + highlight=highlight, + query_string=query_string, + spelling_query=spelling_query, + result_class=result_class) + searcher.close() + + if hasattr(narrow_searcher, 'close'): + narrow_searcher.close() + + return results + else: + if self.include_spelling: + if spelling_query: + spelling_suggestion = self.create_spelling_suggestion( + spelling_query) + else: + spelling_suggestion = self.create_spelling_suggestion( + query_string) + else: + spelling_suggestion = None + + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': spelling_suggestion, + } + + def more_like_this( + self, + model_instance, + additional_query_string=None, + start_offset=0, + end_offset=None, + models=None, + limit_to_registered_models=None, + result_class=None, + **kwargs): + if not self.setup_complete: + self.setup() + + # Deferred models will have a different class ("RealClass_Deferred_fieldname") + # which won't be in our registry: + model_klass = model_instance._meta.concrete_model + + field_name = self.content_field_name + narrow_queries = set() + narrowed_results = None + self.index = self.index.refresh() + + if limit_to_registered_models is None: + limit_to_registered_models = getattr( + settings, 'HAYSTACK_LIMIT_TO_REGISTERED_MODELS', True) + + if models and len(models): + model_choices = sorted(get_model_ct(model) for model in models) + elif limit_to_registered_models: + # Using narrow queries, limit the results to only models handled + # with the current routers. + model_choices = self.build_models_list() + else: + model_choices = [] + + if len(model_choices) > 0: + if narrow_queries is None: + narrow_queries = set() + + narrow_queries.add(' OR '.join( + ['%s:%s' % (DJANGO_CT, rm) for rm in model_choices])) + + if additional_query_string and additional_query_string != '*': + narrow_queries.add(additional_query_string) + + narrow_searcher = None + + if narrow_queries is not None: + # Potentially expensive? I don't see another way to do it in + # Whoosh... + narrow_searcher = self.index.searcher() + + for nq in narrow_queries: + recent_narrowed_results = narrow_searcher.search( + self.parser.parse(force_str(nq)), limit=None) + + if len(recent_narrowed_results) <= 0: + return { + 'results': [], + 'hits': 0, + } + + if narrowed_results: + narrowed_results.filter(recent_narrowed_results) + else: + narrowed_results = recent_narrowed_results + + page_num, page_length = self.calculate_page(start_offset, end_offset) + + self.index = self.index.refresh() + raw_results = EmptyResults() + + if self.index.doc_count(): + query = "%s:%s" % (ID, get_identifier(model_instance)) + searcher = self.index.searcher() + parsed_query = self.parser.parse(query) + results = searcher.search(parsed_query) + + if len(results): + raw_results = results[0].more_like_this( + field_name, top=end_offset) + + # Handle the case where the results have been narrowed. + if narrowed_results is not None and hasattr(raw_results, 'filter'): + raw_results.filter(narrowed_results) + + try: + raw_page = ResultsPage(raw_results, page_num, page_length) + except ValueError: + if not self.silently_fail: + raise + + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + # Because as of Whoosh 2.5.1, it will return the wrong page of + # results if you request something too high. :( + if raw_page.pagenum < page_num: + return { + 'results': [], + 'hits': 0, + 'spelling_suggestion': None, + } + + results = self._process_results(raw_page, result_class=result_class) + searcher.close() + + if hasattr(narrow_searcher, 'close'): + narrow_searcher.close() + + return results + + def _process_results( + self, + raw_page, + highlight=False, + query_string='', + spelling_query=None, + result_class=None): + from haystack import connections + results = [] + + # It's important to grab the hits first before slicing. Otherwise, this + # can cause pagination failures. + hits = len(raw_page) + + if result_class is None: + result_class = SearchResult + + facets = {} + spelling_suggestion = None + unified_index = connections[self.connection_alias].get_unified_index() + indexed_models = unified_index.get_indexed_models() + + for doc_offset, raw_result in enumerate(raw_page): + score = raw_page.score(doc_offset) or 0 + app_label, model_name = raw_result[DJANGO_CT].split('.') + additional_fields = {} + model = haystack_get_model(app_label, model_name) + + if model and model in indexed_models: + for key, value in raw_result.items(): + index = unified_index.get_index(model) + string_key = str(key) + + if string_key in index.fields and hasattr( + index.fields[string_key], 'convert'): + # Special-cased due to the nature of KEYWORD fields. + if index.fields[string_key].is_multivalued: + if value is None or len(value) == 0: + additional_fields[string_key] = [] + else: + additional_fields[string_key] = value.split( + ',') + else: + additional_fields[string_key] = index.fields[string_key].convert( + value) + else: + additional_fields[string_key] = self._to_python(value) + + del (additional_fields[DJANGO_CT]) + del (additional_fields[DJANGO_ID]) + + if highlight: + sa = StemmingAnalyzer() + formatter = WhooshHtmlFormatter('em') + terms = [token.text for token in sa(query_string)] + + whoosh_result = whoosh_highlight( + additional_fields.get(self.content_field_name), + terms, + sa, + ContextFragmenter(), + formatter + ) + additional_fields['highlighted'] = { + self.content_field_name: [whoosh_result], + } + + result = result_class( + app_label, + model_name, + raw_result[DJANGO_ID], + score, + **additional_fields) + results.append(result) + else: + hits -= 1 + + if self.include_spelling: + if spelling_query: + spelling_suggestion = self.create_spelling_suggestion( + spelling_query) + else: + spelling_suggestion = self.create_spelling_suggestion( + query_string) + + return { + 'results': results, + 'hits': hits, + 'facets': facets, + 'spelling_suggestion': spelling_suggestion, + } + + def create_spelling_suggestion(self, query_string): + spelling_suggestion = None + reader = self.index.reader() + corrector = reader.corrector(self.content_field_name) + cleaned_query = force_str(query_string) + + if not query_string: + return spelling_suggestion + + # Clean the string. + for rev_word in self.RESERVED_WORDS: + cleaned_query = cleaned_query.replace(rev_word, '') + + for rev_char in self.RESERVED_CHARACTERS: + cleaned_query = cleaned_query.replace(rev_char, '') + + # Break it down. + query_words = cleaned_query.split() + suggested_words = [] + + for word in query_words: + suggestions = corrector.suggest(word, limit=1) + + if len(suggestions) > 0: + suggested_words.append(suggestions[0]) + + spelling_suggestion = ' '.join(suggested_words) + return spelling_suggestion + + def _from_python(self, value): + """ + Converts Python values to a string for Whoosh. + + Code courtesy of pysolr. + """ + if hasattr(value, 'strftime'): + if not hasattr(value, 'hour'): + value = datetime(value.year, value.month, value.day, 0, 0, 0) + elif isinstance(value, bool): + if value: + value = 'true' + else: + value = 'false' + elif isinstance(value, (list, tuple)): + value = u','.join([force_str(v) for v in value]) + elif isinstance(value, (six.integer_types, float)): + # Leave it alone. + pass + else: + value = force_str(value) + return value + + def _to_python(self, value): + """ + Converts values from Whoosh to native Python values. + + A port of the same method in pysolr, as they deal with data the same way. + """ + if value == 'true': + return True + elif value == 'false': + return False + + if value and isinstance(value, six.string_types): + possible_datetime = DATETIME_REGEX.search(value) + + if possible_datetime: + date_values = possible_datetime.groupdict() + + for dk, dv in date_values.items(): + date_values[dk] = int(dv) + + return datetime( + date_values['year'], + date_values['month'], + date_values['day'], + date_values['hour'], + date_values['minute'], + date_values['second']) + + try: + # Attempt to use json to load the values. + converted_value = json.loads(value) + + # Try to handle most built-in types. + if isinstance( + converted_value, + (list, + tuple, + set, + dict, + six.integer_types, + float, + complex)): + return converted_value + except BaseException: + # If it fails (SyntaxError or its ilk) or we don't trust it, + # continue on. + pass + + return value + + +class WhooshSearchQuery(BaseSearchQuery): + def _convert_datetime(self, date): + if hasattr(date, 'hour'): + return force_str(date.strftime('%Y%m%d%H%M%S')) + else: + return force_str(date.strftime('%Y%m%d000000')) + + def clean(self, query_fragment): + """ + Provides a mechanism for sanitizing user input before presenting the + value to the backend. + + Whoosh 1.X differs here in that you can no longer use a backslash + to escape reserved characters. Instead, the whole word should be + quoted. + """ + words = query_fragment.split() + cleaned_words = [] + + for word in words: + if word in self.backend.RESERVED_WORDS: + word = word.replace(word, word.lower()) + + for char in self.backend.RESERVED_CHARACTERS: + if char in word: + word = "'%s'" % word + break + + cleaned_words.append(word) + + return ' '.join(cleaned_words) + + def build_query_fragment(self, field, filter_type, value): + from haystack import connections + query_frag = '' + is_datetime = False + + if not hasattr(value, 'input_type_name'): + # Handle when we've got a ``ValuesListQuerySet``... + if hasattr(value, 'values_list'): + value = list(value) + + if hasattr(value, 'strftime'): + is_datetime = True + + if isinstance(value, six.string_types) and value != ' ': + # It's not an ``InputType``. Assume ``Clean``. + value = Clean(value) + else: + value = PythonData(value) + + # Prepare the query using the InputType. + prepared_value = value.prepare(self) + + if not isinstance(prepared_value, (set, list, tuple)): + # Then convert whatever we get back to what pysolr wants if needed. + prepared_value = self.backend._from_python(prepared_value) + + # 'content' is a special reserved word, much like 'pk' in + # Django's ORM layer. It indicates 'no special field'. + if field == 'content': + index_fieldname = '' + else: + index_fieldname = u'%s:' % connections[self._using].get_unified_index( + ).get_index_fieldname(field) + + filter_types = { + 'content': '%s', + 'contains': '*%s*', + 'endswith': "*%s", + 'startswith': "%s*", + 'exact': '%s', + 'gt': "{%s to}", + 'gte': "[%s to]", + 'lt': "{to %s}", + 'lte': "[to %s]", + 'fuzzy': u'%s~', + } + + if value.post_process is False: + query_frag = prepared_value + else: + if filter_type in [ + 'content', + 'contains', + 'startswith', + 'endswith', + 'fuzzy']: + if value.input_type_name == 'exact': + query_frag = prepared_value + else: + # Iterate over terms & incorportate the converted form of + # each into the query. + terms = [] + + if isinstance(prepared_value, six.string_types): + possible_values = prepared_value.split(' ') + else: + if is_datetime is True: + prepared_value = self._convert_datetime( + prepared_value) + + possible_values = [prepared_value] + + for possible_value in possible_values: + terms.append( + filter_types[filter_type] % + self.backend._from_python(possible_value)) + + if len(terms) == 1: + query_frag = terms[0] + else: + query_frag = u"(%s)" % " AND ".join(terms) + elif filter_type == 'in': + in_options = [] + + for possible_value in prepared_value: + is_datetime = False + + if hasattr(possible_value, 'strftime'): + is_datetime = True + + pv = self.backend._from_python(possible_value) + + if is_datetime is True: + pv = self._convert_datetime(pv) + + if isinstance(pv, six.string_types) and not is_datetime: + in_options.append('"%s"' % pv) + else: + in_options.append('%s' % pv) + + query_frag = "(%s)" % " OR ".join(in_options) + elif filter_type == 'range': + start = self.backend._from_python(prepared_value[0]) + end = self.backend._from_python(prepared_value[1]) + + if hasattr(prepared_value[0], 'strftime'): + start = self._convert_datetime(start) + + if hasattr(prepared_value[1], 'strftime'): + end = self._convert_datetime(end) + + query_frag = u"[%s to %s]" % (start, end) + elif filter_type == 'exact': + if value.input_type_name == 'exact': + query_frag = prepared_value + else: + prepared_value = Exact(prepared_value).prepare(self) + query_frag = filter_types[filter_type] % prepared_value + else: + if is_datetime is True: + prepared_value = self._convert_datetime(prepared_value) + + query_frag = filter_types[filter_type] % prepared_value + + if len(query_frag) and not isinstance(value, Raw): + if not query_frag.startswith('(') and not query_frag.endswith(')'): + query_frag = "(%s)" % query_frag + + return u"%s%s" % (index_fieldname, query_frag) + + # if not filter_type in ('in', 'range'): + # # 'in' is a bit of a special case, as we don't want to + # # convert a valid list/tuple to string. Defer handling it + # # until later... + # value = self.backend._from_python(value) + + +class WhooshEngine(BaseEngine): + backend = WhooshSearchBackend + query = WhooshSearchQuery + diff --git a/djangoblog-yql(优化后)/whoosh_index/MAIN_WRITELOCK b/djangoblog-yql(优化后)/whoosh_index/MAIN_WRITELOCK new file mode 100644 index 0000000..e69de29 diff --git a/djangoblog-yql(优化后)/whoosh_index/MAIN_cv5z5jbh0nmqme2y.seg b/djangoblog-yql(优化后)/whoosh_index/MAIN_cv5z5jbh0nmqme2y.seg new file mode 100644 index 0000000000000000000000000000000000000000..837c8523a3659e2029776ae6657696e016ce54d3 GIT binary patch literal 18093 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 H&4rAkuBUZf$q{!*+EO zf~gP#360coLqLo=b&lyarfg_%i3(x~gMp4|hL{DLVN6s&O;8kkckgb#%~BF*aOl3| z-uu1xzTf-4?{{CbwEzf~>IQ%)t;jECuV24@+DB#@2_q<3a#1`4M#>0`fLjN2&1>tc zF4x+!nTtQyKfnxAKpjtQ`B!M|Qj##yFxeTOUwLw+!K52seuBzS?d2jj#ei`&InT^u~TzqqulG+%02aheOqbO35tcb%@f zfwNm!D_G(aj|dn{E5F*du`#A3U=BLl3b?=2kEni9g@wm@#n})}vwLFVUcAMh| zv`=(O=l_^~)V=l#+9cc1ObKsPvO9uF6pTufqXIC4XEeF(9+3NLG1gZzSQLZ0n{<%h z<0|YuMia~T+pzm@1q*-9p;5cgJZ-UD?|v-L87zuH-L4L@wn0qWJB{TW#;_cwBbM{L zg5~*N#!|hCgum;(Yq4BQCRR%{v3$QCyMMZ1Ik!qIx7)??ogVDYJC1$IR^c0+U>o^N zKV56LvW&CZ!waie#!>C6bDJ$3Zv+!7JHs0ZKPgP4Kd#YZWmz+4ZH7LSUx9$a>yNd& z7`XYg$IAPOQr=ICYu4)Gjq|)Z_(g6R@Pb}2MkEtUi6)|xI7h~ldU74vCVnw$6@HiQ z%w|q)9b>AhN{=lcG!AWFsmo&gW5neh4VS<8HEG-Oyd8~?&E6eoW!jVTN^*$S`Kwdj z^{MrVBlI(iOzZXbemdn1Luz%7(U<9HuxdeU6qzU{}XL! z>nYL^JpSm4^2}q}V}|ma1EKZ(eOEvIec#Yq?=+9}zC2soy7!femOT|DuMM%;A%`}k zJ41nM*OnY@FQ%b_i{Wo8vVv+;kzs||+2r&VTAFj+IZs(@ootTI)5wXE#<**18?8{Q zcz+BOqmHxjrstG?+UaKOPRx zh&RZAYj8@O0mw1MCQc%0!bdYVa_$Bzg9SXA0t0qT;-=q#E2L_MWnyesDr6Hl+pF^_ IH}bl_00-0x*Z=?k literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/whoosh_index/MAIN_w8vdct7cbhie95f9.seg b/djangoblog-yql(优化后)/whoosh_index/MAIN_w8vdct7cbhie95f9.seg new file mode 100644 index 0000000000000000000000000000000000000000..2e65d86d734a31143e409c5104c06879df1a0df1 GIT binary patch literal 136513 zcmeEv2S60Z_y17@L{an(u`BkjprBY!>>Ybzuh@IRE}$q_v5R2A-ch51U86>gJ@zij zQ8XqR6OA#6|2MmD_hxtJ_9VyM_hjZ1pLT3W|OP)a$`@McUq;kKT4w`&79b%*~H&d{bVH9kE!%`{C)g){% z1smzGND9kl5;mNIO>$T)g=IAf8%n`~9HOK!XH&4C5frSQ!vZPH#S|=MAO-8@uuuxi zVhR>SYqGAxJSoh{By0#Jt*OI&Da_F%jIQo#4s)e2JCiV4lX)B>q%c#4`AZ(UY>ypc zr7(Mw(r7Cw>JTY~IhcgeR#MJkjufUb38U*RyTfcLOlu03hnDue!zw8(mq{3{$%76n zrLf#4VYEt4Iz&rhIZeS*Xj5MAuv`jrHwDW>t7NCc3MnjyDOd_^lPevTNnzPd!f2bE z>99l!`_FUz=eeMh`z46BlK(sxrxLoE{^z-fO8!rHt~F%L~NOBR3OC_AN{f(}I3U8D5?tu14OIA-QH|i!OFIWNhm` z&4SkS_8QaGt3{yKkjY*#g*64*^tbWFWpY_ykpKn(#xxl{4#p^1vv{#FRwmA%;@C{<}8Sp-^43NqpWDsG8NbT zT~^8AEprXk$1!U7Vn?ko4#XNZJy?AgH0U4HaK7g`he&m#KCDudMZJcTzRQ_MdU^H1 zUPdoJKc|QE^6I1V3|{`(^PB~wmscOXXY}$la^{s@-pa~Rzlq3b?nmX!C(XV3%|-?< zpY$oGr}XmbHzgUpe21Jm>E*4g`!DqJHt=jV5P_Z77g`6l$-TAwzU>AWB0l@PwKj!e_CLc{nxZpYgszBQ!8KI%1+G6xwqEk zad>R{@^HWP4~EBiU*#NNn_+?tTGx91CXsnN%Dg+ADZ5W8I^3(hV}YnE%_>~DRJDTR z;GnGK`VFhx?}mdW?@H}c)RXP}y$w`m<*wIuy0UUXY~%V&w{9{ApV2!2#jUBeF8{^* zrZ3xgY~%K<+ybm`L)MpI8#A)<_{dt9|F0`hnJ89HBU;N>|J$m;TIOnlvDd#t#D7jt z{?sSQIB9S5)@CiYVVg0A4O)bihcW+()?h6o`d28&S{;sU4AaV0Yvs#ZS@+huyzShY zwMt;+miy%^$Oa{_O&9#%T{2@G4>h8*a!aty<-cq<{e|Y<1}?$|BCPKptS{lq9%|X9 zAF#3`vS}f#>@dFU%YUImMl0K=4Ls?WUxI&ABerrgu(FS^a_;}Tytt&_cDDjwz6-Ll zhqKM)t<`e>bDkz%nz3CA`?3wlHo5=L_5TlCKUS@^T#xOZO4`QB*+z=(`eSR=yOquA z%XUb%F(NDL=sz1}y@pGzuCh%n+n^e3Ai_58!dlMGcAcD++q7*=)^_Up@-5c}C5Yo+ zWwBSjaQ`}JFzY=Z^;cQ?!Rs%^cUc0pPi*tfkCj`7l`n6DYPNw0D=X>0%d0H^MCDkk zi?faHzwF$9+4C3H(!CA*jtxXuf2Dx+CD>+kXJtoZeKlFx)!D#Uty}^t*RYjyZ#(^4 z%cI(8z;3(Sw11-{+nJfQh8;F2fel1_+0M##EyK!Q*JjT%9po69ay;pR=&K=yq&fBek<$81_ty$i6v))a@jzHl`9`F|6fO~2trMTDE_kR zz{*wp-{ln#0*nE;Y~UblAmV@GzHQU!zR*7VU!fdpbvjn|NVb`|w~Z7VI1ekEs%`Z2 zubbtyLB-oZgq2(RmtO)K*{zk^_?KS~R#woL-wte7#a15ieW8OID_hXN;_}wA92?la zjrsu_l*9%iY%`>^K|yTO>sYH<*e3VZ^4B(d>R_z`*v4glp~hpo#%ty3{ZIdrFHb5b z{jIEjD_{N#tzIkp9vigYe}@Pw*MpTWZ-Y9(5`5Xs%*wg9mW#7N_1Zv$mD_-oFW;BE zt_UB3ZlZVBa2p)>wg?zIN>gb9_W^JG9`wlIULl$ivosAi9*gppeWGxV`^=_3g$DPU zQ?cK**OlG`HNRE9--2Eat|@##)_wau_Bna%>tCgjOI+Ey)r#y~RmWlL%;H<4v|AhM z*3Zlm)T8LN-kW-L>{hhn!}{U1Uxgoi6+UH>=I4c_SK`Z#qxp9#-J0lK#7w%-ndH79 zJu>(yd@3>6+2!)JPUlw^TpPP~@v3f@maTH`Gt$GSQG~ukbWYzYXY=?B{C%JIq^grI zZhYb4(`1j`*)h3W_`J=Y?d$ulU(ay8=d-eyqt}b*buW$`I@Tz3&b_K3xYdmjP&eGEP z8)b1{t{$22>7>T#ryTC9;&v%*|LKgTK7~2ke?7kGP0sM=B=d%Ef4PraxqcUWLHpR+ zFKp}0*D3Gvw1T#ARkQu6OS$Bs<&y_jPQLA+@hMoSqqOuAkL%xp$`SK(V!uA+S_E%RB|nI-WLvJ!q|561baB>Am+I5WWa)-j zP&%XYDb-y3dLq`Kqe+Q_GDTv^t=h-ZGTNDxm^sd;!~yLClxT4kRxaKb+g};B_qjh* z>y}x<;_b}{d)!i6A+v;ya4{n+`I5GmR9HrRIQ>n}1r3h{Y}Y;4 z`?_kA1HGI#S1WL>XzQqIoddmsCwsM->=j>FlOuQ0ReX{E{zS4N`~0_)Fj5S^cA@pR z8h59s2g~&8sBe49qg&MBz_U}QhLtM(x7IVDY01ztz5c%D{ItZ+h9&o&>{wD`NwZRK zFLw)ik!4YV{y+RtT3d5O{fBewJ#l_>rpUZozmKhzCAIp)pSRuFr0w|8>sV{Q)l+_5 zay{|#CC}88AL0&07up=_@Yb(##MF`3Q%b(^`D)LhGL=Hh`^C?>_;l6fm(Sex^cmCf zXx8EPj#hkZ7yM~-$-l0xNp!mX>gCiob`u8nED~AZ>E6q&MrqdEol>r@!_{HKBOAQ_ zHl@X=0!R0K=rYCO@%<^Kk2@C`I!#wE^lH|gK~vnOYc>Zi`5G1Ro1h44$gEUEJIDRc z>=VlmFLQg>oC1j@AJ_i%-P%O=zJs+bvnMZ{s%ibYNA2jpPA`kB8r{$5ZT}oqNB&hs z8+3zc;^z@pO8l8t{KfRM*W*3k-<)u1e~Tr{Y86f_RC8L|%w;v!J-D*v^xCV*NAC0* ze?DK8I|oJ{kC|g%W5^u;tT|(=H)`9*u3NRUi_iFc<_2B%WT8DZJ1)JE`l|Vlp&wJ`J480v6ZE*o;u=mbH`iG7`c(V&vCU#TA3~8W>iweeLG8iAowzar;}-;bCkCYz|okl~5*XRLS@EnxEF_ z9Iur)&~d}bYmS+Ha zPdBBOf8#sh`G-zZoF98m`8}oYAK4uLT=W5pk3Fs>T}8P1peaiW-4Lm;jJj`Qzcj+h zOedJyQae^EOyYY!V<>MF_C7AfOefew*Cx}1B~3J=#?zu2ml2b-Yhh21%j7o>?6JIy z@y7RK;N0qMw)1yt)!1XDubz42#PVS$pHXERop^8~rV|(M3LnkYhW-y^%_FL`mv&J8 z^gWn~kHb@Ue8CNwCG&M?&|eo=va3_zsybVvHtdS}=2%pVoSK+J`Nv7inbFoj>9jRd zvZ&Js*X51Dl4fqkJ{^D34a9US7C zp~&!G4z}TL?8_z5H}>796<&;aGS0IZCySW#Y}{mn%Pfb6A#seEwx_ej*@n8cecQ%I z`NPD~Qk*#Yq0{;N9nLQgjr%pQbYR)ZPJwI4BwLxvj^1;!_E|bBc;@@KueVJK?^d)V zJuRrR_Pu_PY(O~oVzH5#RrX*r(>#w#iDO`_)Qq}Lx*uw$Ua5|i zbv>jOWQnk|>cX7r>PBRqu=(o3oL}pvqOcL7Q!!4ID?RndV0SVH{V}I|*jyTovyw1yMQ9u8iCv{!VuS@Fwa_Ydj2{RLVK_55EdN^pV>iujLsL*@3_7p1{8AUS2Mb(4s7!DH)+NGn6vS(*|W)MJE~5 zE86M4P8hd^i4{$IYHA9W?>(3k`_%a6!S#>V4x>5;qB^f-U%oEjcJ`LHW*?kX%dX=$ z{WZ(>ID3rV?=kwI=je1h&8q>0g@$DDfG1%n(_4w1^AEGM!h?*=7=#RDN`pbjrV`3Q z$g-FDy|HTlm$FgE|9k+H(3M$gQO9?xYg=b(EB*M|enh^XcdED2#brJIls245|=$XoPX5g z{EZ&xcQ|Xh$9tX1tkSWYOp{&qu}WR=?eIsIKcIEtw_V?B@&1l)+O%ebe;{ zgQs26!P6wg;AwjOV%?;L|K~>iJ}F(jS{*m&`evH2xJT;3T%PD=NrhQ(mlRjWjIfcq z@PEB9%l-Norm>2C{q}ur3)G^;vVwc5%ep&Hi?gSn7KkG~9X~XITN>p^&%HNeq-S63 z^dw=V_c-R<$7`-5vW_@~{YW?VXfGuy&pj;Vw9Ihr30;^aC1Zpl;uyi9eHUGs%UKtv zxRy&EUO9PC<>XrqnlhWcgo&U`xSMHZritX#O~YbG3PV9^ZdN&wp!)D2VXCyy?pqha zVg$TrOq#Z?9Xvv)4UZ6-boClA*=t2%&GA_UWQzeZ>JF$0n(k8J@}&@u#%O0s?Kq=7 z3MH$Zx~%(2+RU4VwKFp+No%Q{f(5hqMkQWrM%c4?;waB@>r66pN9y7(TBpS&8#(Ux=gFH5w2!RmU2len~VA9mY>jB-SY2z(6-O4R`!2X)u5CxQdT+KMvc*FDu#>dxnncBP=U=vD>pHD)fIQ7#m+k zeY5e->V2GxUN{79RU5yxSy=?odJDxdE=Dghj;0DM;4bsM`8mmj>ec+zC}D zI8SJ@g%ojPD<})XD65F#$=kX zxbCt_PB|DrYFY5EE+^%;h!&JA1&uABH>=hHntGDqRL0Vy&nsq0r^l*$jL8EzAuE$oUuS553?~^Ww z6JQGt23&a;P^pgQ#JB<#v8exJ@fJUf2sX1k@KH{!@SF`7mq1@)eEcF`Hp8|f`r*q} z<--@*3etXWJcQeg`I&H=FMA$~xA`!&QAnKH5Z7QVnw`H!rn&PZGf&(d`|En6urWe8 zDb*^62xitrPzw-_db1ZGoYHwYw*B6*?e?Up1CJ!MhXheaPY1UVL2gnM<$8%Y-Hu zNjNU*R}&XWOdWWr`ea-nAuJN47f7tiwf_FcYeyLiBzE^Ga$2hGjCvSj&uxC{>W#Qe zBonIE%q^{>i@4gxVtcs7`p&VX+oR6k`vz#78(O zL&X`7FH2Z_Ni!u&8meuSS#=g))r_!bJGHVU$QgB@w1NDl?q{4H=_X`a$^6We?8#2? zHBpP7@g)pX@A7UJ6{{>$W~sWK>FTF`8&$fr_LWqX7P!Z_WoGK_ckz~#bt9u3f~wv} zy;r<-inCPTxzz2jsjhw*til`wt1!j;sGqhKh|0XO-d1;F_OZIQQepqxW5#=!vC*V? z;_$^{C-y$>v3kiITIn)x#w!EDEbiojWshLxPeC8|(?(=gmA#KEtKJqIONk4hx!X=| z;bvZy$N5pLhbFm;ogOa)5V#j}vFr6CH*0<0wHUVfXm%ihJLU6uVLAVYqAho(J=C4) z%{E%UOsmc$bIYXMGjUB;(i$@@aG5wj%A7S>Y)uLa+AoV!Qrv>}nu;}9Q{NX87Ni-c z7K~2-lzyGe+h~HFbGX1%h%$&sm@$Y*j^FCuT(rIO`GTjMbeEe|xNxazg?@v|_rquk zv$h7!+IIV0>o@N-9lLrLZy4@T;QM|LR8f*w5SfV$UmUaFgfO2q-nKbW7R=6SoGuH~aXK=BUL z)kTSxdki!0e%%Vs#F!XK=I(Ol>AGOSGUbt-{BeNz$nI^Z;*p)lzJjumkOhMibL;mX z%@Y@xTizPtW~sYIy9&BysMSnp4HeZ}gUc{oroAhe&_wEBY&zW7Zv zmuyON$s1TOR@w$L>dz=g+S5!qH)w@7qAjjF%MhJx{bojer?Ftc=9W8b*M>=z zXcJi-$Xq`c*UPw8l=;3P2F=Qq*CC+leovoL=Srt;*;vYR%%+skyxkzUPhiJOv-7X) zlPzDhqpgnJJDRgqOFp{S;P2)Aa#Tp(?_AqYPt3YC{A$<74;;77hB#kQT%4~!_w`X( zH($FSQ)p{gwvA!6wnl9^7L{-;s!dK!mZY+>mTQ4eDq!Y@>3Mdo5H=(;9{RMB+O#-0 z*i=JyW8X0D@wia z*f&69@Q0{op}&N=Pb{@EbmHU3`qPQ}a)~osC*IFC@j#}PK8u;=mDEz(Fw=xNni2M> zrM5(-39DdE*pJ$>Qehdj8KWBCCz+W;vP+f6b+ABK+$;5#=X^^SA}!fJH<0({Zd#l? z#g}(2AJwy8ClH(Yjn3LiSTKua1)FmzImKtpIC}Z#N{p{%#ulGf5Z4oD!dTagE!rOy z18rGeGIuj2dpJ*gW8d-qgi>QYxl!gzb^K7dGQ0irE8rr<=|=I%&GE|xgkCo@Zhn)7$!bBo`TeN8 z`7Q9F;7Mt}n9=(-y2m&3gv>dwPI%EK6ZAa7#7o<}p3f@ve0N*{;YQzLk6}u<*e|DL z*9voqD9nOZoODc9rSiqh@w(Yqi z?^mwf)aI2M=|3NLyiW>O*JYM_;*9em;-u_az+zvclTt4Bg}YZ}%n_Y&`E<;^m~*vm z)T)5`T*TIA*cy*&nWfK!Y3lmCxnC=+%#6r{+qIEQX~OfBVakShut5PKU_?J6pPRrj zu7j1`E<$Xu%3RQ7vX*M#ymtZL$s)Xz4RBvSCq2-i{ZOwNvw}A!1maSvDvVe&D|4;C z`|%nTYo>JInw%YbC4;CX?kUt9 z#Z#y`p~VJcetL>Jqn|=4!+mnkp-MP8vxC`F&!O`CQupBslh2_Vw(tIGms^KRYwS9l z%GKd~)(&3wZBJ#d+UC@QhaUs$1?KW>nkzVvL<1c$*=ucK&7Y0S2vfP1JH9wG<954q zI>C}GcIoev%)K)5G!sJ@B;8VXLr$UMY7!iAX0-n>`d72BQ>ZqBrGv0r>p zB=c6JnVn*=A15wT$((olhcF9A-tDh0&V@R(uUS~}ZohwCFX0uo%;}+LT<=;}y@&RG ztWCvQ9mjil+0#tQV{q{o`RCTAf_k|a*Q-{1zH2eMi%at9@u#!P1kEh-u5Rt}uxh@J zLz%1KGVXOcf2+s&UCx@ek%bp#nxO?T>%wSghqa@nvMgvoZ09Y?x?V$D1Z7$7^US{b zR6-{d%yOR>H%Q$LIrbCZtFXLeaprGnB@-E%;U}5>0;~z%O_#X#8!XM zQGDk=6U@U+-8`J<=q6`gjhX9zedJG1GI|?e>=J{`d_LvjQ0+u%!7?h#cwZb}jXfbC zx{pUY#djufJTAMJl6z{^`G@y$h1ivrom)EESh;lcrFQ{Yn23xP)~Hys0r~V=A*7?l zO(6raGQoM7n`kW|jx{u-yEPpM{~`&5pXC|^!e6$%%<(5>I)s)xzP9JJGiST+^_tls zcgyT4v!-dvf2e%oQjdhz&svs>z7&1$(wS_1t6%B=Tbs>edz{|5V#;y1#e3`J-S#GZ zygiA79|>{ro&SpHQF?8wx__j9+j(nVwWmMMeLwo2d zhhFqsakl)^?Uy~?J#;@}s5{V*jP#KGVHq4^ZI$9JccKko4Juxak~!rGKwyJbq`G|jp6 z#WB*BlhJ;$$b147s+0Y-BubcK zExBy|DC-QJ5ab{e8j6_}*7hgli%Bi1v%k$eCHPBR&TYB7nW8@8{9&5t#!*&AtIX&| zO+;Z9yNvrT;;V{SV;Pl2nMYDSbz97mRo7qIq%9FE(&_5L9DdUYA4U4izOU%OwtBm>r6c0QzB>EnAsk-v9T7nODZRpE&b#{D$987ik3_f%({o zbbis**J+o{_BuAL((0pbOD^m`cd7I@PaocWcxit7D>Jx{!0hSucKw8`74CP-z2a2= zn9gTB_6#1=>Zt4Pd)++aXB6-oF(={Vs}tRt*V|uwcu1>{lR7`NfBz%@DVVp5YG@w# z1)n+B>rRSxl*^j?Q%e05n(EgxqVlQoG4W@sKizdX_}S#wUP;eA*M3{%*WQbTsH~QI z8#AFRwg*^L+b4^%SN3rX>3zrtfzaQ^-2QODa9R=m5qM??XmJE=BLgD7GS^eKNgQR zlu_qy?EKBy>-8Jrny^fHk+Rm^TIJN=Q}ElS8-&Uo&zMV8*6nA{B^G*FG0Nmz;tXys zu~Q59GRaj<^D&MPLEdBZ0ngDd?cn~XkPy@pADT-B0Q8@cL6=> zXp-s_KOr46Wz_iS%xsf2JlV~HLxT8bzU3nebFbt$ozMxZSS|Npab`;9I8U7Hw73li z%T`Ux*GfI|&AbKk3G8U{;?2T!Z*2iIk4#ve8_a&X%suag*!49T%X1SZx| z$FdhDwA`y}g(bvBkUvN*sEsL9;tduGPCN>>AJX*!SeBf zxsOHKMe2m0$#@qaDcNTY3+b{&vfY37v73&+n5tnlQo>oA3?G^3jpF5S{Nz5^+ z*sI^)F0Q1oT$Y(t8~0mjg&WDtc%w}A;R*4Lvi=p6gYD%H@(W)nvAmdO`h@!zw8GqD zrp&2)eBJHmWc8*P^qog0zL;WeKA^jJ8)tF5A5qlII4pUnHuHu?N%z|!YmmpWmRtu z4sYb|t7KG-#>SAqo*NPSq3g5ci=Q$o%UES2%vD+HC9Mz~&Eno5!ORM>8)dYWrM75E zjhR{R>Fk%86CIx~47HfiDx=I}lzNN4`9fO@wP>-d;7;nY9xM^p{AEHLGxHqVVW}9W z$YN78w;bugQ}JbPyz_^b66n?6zGFveDoyAyq}MM&11rL6dFF>u={x^>UGK!yQ@`^M zj1*sEwcI_%nd!hCN9lyvyO~gR=9aBpmw$xEl9rueVHv$AF#5;$ab|9k9jodxt^a(V zG)}#jaULqhOR~6WCz$!L)(;P~|9wm?e#@zq&A|82O@TD+@EsUy*!xXT_A23kV^sjFri5?80h?lpwZNL@TPIdMVyww)v~YC-C%nTDu{ zv_(7NT88-5KOdc!d~AO5;RUJtccjl=WZ1hGuAF{&38Wjg%rzW245z%S*6=nQ+E0=e z%t~2t(8m{!;8aRP)bo(AVmnv=;T9?u@G|A-7`qGBVv*d&myHr3{Otnn0#ad$?)!jJTt)_Ih?v{ z5r{BE90XL_`W^9h&O#;(;Rhj?hRFG( zhN2dL-XU{_#q%(6`5}@RI|~vy9nAo(k&7hkg=-p)?KLcc8k&`|Ya_5FA6}XoecZ5d z71RN*P@*7CHHKsB4M!J(IG-w2s`3>kmK?MNg)xM0dLA+-IdOUFvU%yDU|3rWQS%MQ zmOT%d3-X{Ik`w1A9|;F*0u>tI?CyohN7stFPg%VOYMbONW{B0{PNj`dCQ@Mn6riZ;36q2)+HZFNL{qYu$$D(@Iih17acoj?9l#2z5QKN z4$Mu9UzWObYf40dD|f2zh~Z=V4<8FB4fD7*VA#0Lusbq+#a5vW2*;^Q_ZrqNFf80d z1g>3>vgs%oQ2LCmhKO0IM`nVVk}StYrtFPOjXsvTfK(i0Cq3?n;piqPB{>^%Bz?!q zs?{o0Pu=?ssW9Qv{N>V@o$&MH&V(9vAFC=baWaz==fbrO5s8p7sGRhb(QrLbO8N?} zez_k3EG;ne+^($mLEz9+nF*i3~V+fJ|^XxW66oJsY{Q5k#bqu zn0EXSsKgMl11b+pkJQ|JFsQ>RdlnhO_Y&pB0A#jdU#MuFysaS5#w~`J^{Gdeh&;qH zAn{Om%DUNU@w>YEbnoij9n?n}ov1?eO+u^Y3(uFF7{#s)pg72%=x#`3j$NIyCo%a@ zlwp1-=#;bN2=8j%)j28>xQRw1pe@ZOtv~Vv2!pFYuE~YsmxzgmsQ9!K;H5$h3s)Ex z9Rp_uoWKUYCuJsSDrviqr|phQ3jvpN7zBe28;-|;6{6kFTW3g&NLw7Ax(OOi7Y{l${Ji)cZ(gV!fpYxdBRZ?Oj;Ah1qlK*AlhTS_1^H-%t zZcC3|4>p>*gKLAL;ekg42ONJ0Dku5q3UH7qOOJCGtL6`a`HS(_GQ@68I}x2e8?5el zTHHKv70jCDy9QEU;fas~-j;|LK9It7NnHIyhOmJp&PiRc$FOUqtOo_1Kq44BF)5)FO@aE}zZKeH%9@$rcX?Ay zJ-*S{q0V1th}~1&hqTi}-+)^H*F}mycN57H7{H!|e36qAXFv-hoeA#+BTg9h&P_hF z+Ax1c^08>}V7yM!Lk}2^Z%Vv~<80Ueg6R5Ds~);`)GCLr8?~yTYeubN=z3AB7D=tB zDTdOET9x?N-`A9L_}%`Arkw0w88|K@{nxZ<`=(VfI0N@52mBV-X!;BtF`!cK(PIbo z9ok=0e-C#mk4953grmrhhe&BOwSjhky|~8CTi~%1xk>O&4B*LeR)=FpOx zB|G^;)K9ZBGQ%;t|LW zo09>4OqQ2nl9WGkE{Ir`NiwRJa!$_eRm7U{RL*nMund!=+?MkxH7p~~z%FdgzXN5e z1u`s>a%e7FVUCpFbGfMkWmqHS1hbM>Y%0SH zW28J{)&LbK!xky`m~|pTiCq`hIJmiL^m-t{;fn(#JR*Ox?t!1dup_&76^$N_V1w=u zM_)h*10+|{4fKIsU}snv<@j8u0BcW*oncs%uXBAMV`mr><=(Q@M0Vl=pr~X9TgWrC zPHOB3=gF3hj0F0^F66$NvaqC$;D{>QpFoqs3fHezg<&jIqsra`m`QO(fH%WLh&ss* zTXr(4qV>bDW6H0(5kEt-GqOXuQn$&-E@TJhumr6b^+RRH?Y`{#jNFrJksY=i{_sO* zhhfx2(`1J&$4dC2*%^jRIn^BRkzL3=%&)2DK4&L6pc+F0Rot8hjvANuM-4PbMr z&S<@q_2(A!Pnr)jNA3}ps`JTBDu6g2(x?G}&jK{{Nj|wjFt%Z07NpaJOJ;)aSltft(a8}rK(|{rsZG^z=rxHSGSC<6r#F#_~ znWa-gC=Gk)mN!JjGMZTfXZ6A$b#vLmn%sO37bKE`>}aDg66cCt5R)>6$L&%J>Dx|DW!{J&vcp#R1pJV^iLLmsDu0o}$S;Z@ zkJ{8Ba^J!|(^73*MTl>q8yEMOQdLUP#(qO#$!Wp_O+_P7u2&z)NE(3&!5R}Y4`c;J#tDu0u;~XUfxP-0PT%bti zgyIV;D%4RwAxda#0tz1esRE0)MWC@zutq=$q4ZFEKR_gUfTyQns*n=oR$2lfPxaLy za_7&jO;D}V5_0FyJ+f0up^UAh-1&3Mg*1A|E^JU}rR9_)&YyNQ++rPp(dcTpEAT(1 z$RARtf|9xCrb-Bvu~LMc))@ErSqY))rPQ|wL8k%F%vJeIdm%qsn)t9#iJ~%AIz*Z= z{zxyl@q#SF^9MiMja*eyrLyA2HTJqVJk;ETw-u&pZpRYRT1TD0y|}& z{K_45NVFV6R(vTTz$I+ue+P=r7`I+Y386GrL8u*}EU>JNHOv-7z~2g_UT7)YN;r+4 zXMt-goj}DxaFTKY{8|ttgk+2u9BdV5z)v68g{tJ1jhXYD6%Bx(^~|mL5prboHbfBF zVXM>-erO1{N=Y5E0U<)(goRD2sLDj3L=ah*p@a|xpb{$gmP5!2FC~O3PUVvd2rPF{ zLMSO!ipU{k)s7NENvT3^ge7Gmi~5uh;1aefkAUh6yI^VD(o|K5w_Xk*E37mm6*kBY zS{lh1YRr2B(0yPRs|FWksiJ&H%O@x?Z)DAlaCxKIP)hR|0PM5|xCKG#kna=_Sb(d{ z7;p*2sag_fy5Vpu-;`49fsO32Rhtp^9HE5Tyuu7M3ol zqv8=I^aTP67Cfl}eF;EPD6*hZ38D1hJ4_BCi!Rk6m*kK=upm?w;#Xb<;g(}7A;2YU zesh583%k(WM5(tmzgNIZmz`VXt16;;OSuTfjWDnXW>%fl3o!sOON`MbRr@u_ES)4v zWM!r@OH_5#7%PKtOYoEsTFMPMgsfLpLMSQzK5_`T^;U;0LWp3=pLMtH|5_<%;}%sx zHQOj5$B(H)b|XZnm)KcKeqa%{T5dqmrWMPWW}(zoYb5ZKdK9j|c7gKxH2+oP7yKl* zK3f%1yOK=Adi5@^_I#NLZgIRu52>(0UX-JY+CRb>+I?|LAO%LI_pZ|pAhZF)I?C`w zC4?$_oxMs(%z9NwU3Y{CrUg>CHP`B>5lTUO7AhfBOR0NB2|2`=`J{?duc916*5fOs z(2#lZ;@}c~b<|5l<$}L3MJ6t$=2zpZV)e}xnS_<$>X2{Q9;o3&4CNgmgAop~n z`3uc+_i9+%s)SHwZ$O}Q*}2uz>JY+CcCqa0POQOk8Gk$@OO%;4BsUB6_2XBoDyrcW z;HNvUc=Z|VhR^W&f|j@!hm=JIE@5j_A1GR}-1=Z8gi>syjR2t)%Pk>Sg)}B`8p18R zRxNwuJ^-QZihCtXDFwKMt?_xF=&~e|H_=ofO~@dJhH&f9l@O}u7&%QWd|lLcnF*Ax(VSw>Y#%gQnc_wJk$ z0$jq@lGrD0(%g%A>X0`w2={K05<(TfRR@4j#pmBlQ-^#bgK#f_sX|)kmO;4Jebgbc zdg0%?P(r8{-C9;JQ&iBRxc^sD=Df{+6aCFJpjBdr{t$J+(zax;Po+8{y^d} z=o;Z(H&ch~kU_XNZDTX(f0qR0#ntQQTXgDd)+*cq8P?IEJBA z*ZymO(5mBJCsRtXH%e)r2y`FV(K~?@@eMSkECM7uY#s8$4=sy(r&S5znE9U$6X7qZ zCc!>es81<$AP)g0BFKwwN)eO>I@XdwxHlP<5UL;@S0M!Z4tTqXf5BXd0!Cr$_yH(V z79)x@>P^d)C@OoMx&eYN5%-3tMh~g5L8ho~8ui@i2%I6^hhRC}d*P~mXy;)%o8czmPZXy>X!sMiT`tVf(5VP(*JcguExJgpkss2EIBC zG_5r5oogioxP1Ccuu`lVK7fT1LKURnT985)gnPGK384zoPiCV0JJPC< z{=`ISDcrl$>X4%dLHnd%w^juP2~{KLd6D{vC`hOmL22A;+e#6T9bpR+szwm8RDJ4f zfV^I~*d?m=KY-K=v43pTV&D>G#;DpHr~?G8XD$keI%JF-LZX1ELw=A!xKJsokU`!E z5sD*3S5Zer$pw+u@0AeBI0yYK7ld!@tD*+CRtSPn2O2%3!UhUPuS<@wIS<|iG`af_ zON60zR8d2;h!TvAi?k$M-sq@-OW1}8Hw6^L%#)NM4*^V@0T&)gHDg0-0ff4l;={?X zA)pVk4UK~zGVm5!!Ripzq1rG~05Vh)3c>|NQZ4(i(ZEjoKrW7uI^>oN!iAtvLMWRV zUIQSsy12kkN(gWX+wc`Y(HY|+izp$qls^DMOW~qVscLw{*8m|J7Ho`zn0qN;#7Pt+ z)XOf$lNVqSwvk1EqRYaC>rgGr$S{DAvIrtr>+^}3ps9>ZLVlqjLM#?lDWmj=5)6h5 zJf?&Im#~dm3lu4fQ4k-iOcgbnWRuna7Ya%Vp-MEmKS1c(=!|hen3NDwdelI0XP}9au@#7+tJG1l=NEkFCRNA; z4-_QW3>PIw2_dCN4NQf^VA`vYKQ>{B3N&fP-U4Wn}ag9M%5vt zj%dAc@zsk?_%pUM}IqU+vw?@yOv2$@j$`umG4%^IM;b%1L0=tir zos^F3u!WN@nP#u5WX}pLWQQ&MF8mO7C)lB=lAr;;zSNKe&Xa9cbNCqwyO13S8lZ0SK@M2C~C8dq4aP zgI&mwud=|TZIT_f2ru}d_2Z{xC(e)Tuth9^pHZ+2*`b35u(A_LvO#C3y7KzuT4aYU zl3bh4P7NhHxgyzNi+m10G`qi&9ma%0WT-hEkzL3=9W;QI`#I+TKyohvsGtEXz}#wb z02MTV35b&dBtZjM1~-p%laxZKpaD$w$-qw8k0fXSD?{^A5rFnX1r1=a&u=efr-BAB z*-uE>sh|NY>t9eF*-7((<|qvs;47FvoD@cs3swL<8+Ov50U-|>;N*f$hM0v1?656_ zd2c(ykG0GN4G19p1q2ju5_}K^h$;;Ltr0+i28eThED4Kh0`n)>`Cidc7BhfVaf|(d zoz$}tLQfB{l)HGd93qJsz*6uMQVNL_Nz4EyBt!urF$46F3Y%R(fFAz9W{*4kS@H^g z#=y>ZJ5YRi%m9|4rM&<_OqU-R8c}r204DGf0*TWC8-TFLLiX(a1)Cw+BYqaPWi{Yu z3hbh)B{2h7s$NFCEXkV)k;DvORp|1fz)n;x=1P2b*521&4<~TLTrHmu$4g-sMes2L zLO3?k^Kt}##FHz$;O{2bMU63H2C(wB;yVCI@@9Omf>r#LRe@hpd`ZjzR>NGm79eES zS1gVsW&le{G+A{bks^s1z^eM_7=Vz1h*C)KS#fm3f~+E}5{M*b024A!0pVf>tb=4Q zeE$G_2v5N;*5;~bKu5#w2|H(#te63MJ)Gqm5l;~-B|B^}li_DP>_uTWbp>V20G487 z-oPbDkwrUU#0+2+JeG{rq`KnP0ER#^WRzvbu@~XYEZD^wk;DvONm<<%*d_HYi5b9Z z!mEz~gfwB%!^mR>uuyA=kCilh60u#h7MAMP9KgJZt@yAo;3KY24`(H=Z!Kw(q}IgZ zOJWAFM66u_?6i`lF#}kQYaQvV7g18AF#}jq)-97uArYU&va{+Xj#when4n}u%m5~e z+~X3IpfM_D0IMu<P%}IizC-unM(tK0xS(b665HfC>2^hj1|i^y?s*cSJlzIigMd z;S71SDwwo1W&o>BH$4INIW&ZX`4;uYGMmkVfSs;WY0Lm$;a&;21RuNkHqg^y7cwS| z8NgEVmX5$qYfKt5fR(W=rxXwfSud7_rR1#@0Yb`xO@MwOo5{Zl`O(spF#}i`+eQY- zl*VK+16YE#jg>rXdS{5^aRYAMHmqR2m16Uc`?FSIr*!Y+MdPs$hc^9yI1Dqi@>q1$i zF#}jq;yr+!mLiQAz;XidVF01}bRlNII!J~Jgt3{Pr{EXIX7PUmy%=_(DitvUSW4SN z`Y2k@(wG5E$e#eAizAI0z=G@*+@O#*Ma%#uig-eaAW6&sRukCQKn~$z2B;bHzC8dT z1}#)5_lX42I9XD@DI=F6i5b8u%Qv!t3jftBjUFxpo1L$(o+Id={iL^|ElnCTfMsd> zi6^9Mllv-*Acc9`xc@0YNOvPvjXY)mYs`6|C!$29Nn!@Dly=}TKjF$46F3Y(q3 zzn&vFb4HUsNTwynz%EGPKH4P~ht+Tnk|8v?#}FXWm;tP+Ngy}Qw3%Vd06ip|xE)B? z1ZPN%ic%yo16ajRB$Fqk_=28=xBpcwEs;!y5R}jt2q^m1D3-WGxe+MlP!cnMrH4b) z{Fgoq;4 zr!|fewUTKKk>40IfK?qwW93TZoqK+yBQ85EpkP~H<5GrN>6S5p3LcLHi16cKbl6V@TWRc%E&BD6= z$&oUCYNZ>K{}J%hHNwXX&_gP0%mK!!W^jhMeIZL!%m7xUpE?4(w4F#}2C$suw`BlA z-D2>cO;UA4-)@mhk;DvOmHo6%387*JFd?A`5ll-FGk}TuNhyem8NgE7nXUk#>jeZ+ zF#}jq&YY7=;bI2pPeL+Zl{{q+M`VZXY&G~Hosn1^A!dLoDjrd};4e&(nTi>}%H((D z03#_E`I?+qvrLH4WQ3kV8Z&^Uy>mjV5g^i-0jzuHbEM&rv8G_vBxb-mIOcm;Jx7rr z?E23Wn(kqxF#}jueV(urZ40^LKKUq?oz?s=xC1-gcBC-_SY^L3RSqFvT+`?w6*lHD z<^t&@=@z})7&CxXBj0xeeo~2ouBey+On#y)+KEvy16Yc>=nMQ)=<6F}2C%MwaW7t9 zP^>g&086o#3dR3K(R{i2Wt4GEsDtm7!|h^MZS z>DB$Pi~PnrcUIM3YXrP>L8LJQSQ@^z48JaxSy{3S*vlwA=s zfTiT?F<=s&~Ehl?)<{8NkZet+P^y zEM@=;a@z+WRE6>%jukV;gshQ4q%i|nkUOrjjB#IT6s54*=AB>#gpL`&l#(omkk44E zO1aw>A=sknm;o#icaH-usgshN3q%i|ny1MU(xk9(h zf3aGW!ZOJF!cbg*a9?azhmg@YT^5WPunv;>S+x+Jf?phmJZKK|O4vywgTa`om;tOw zk_XQKLk+WKF#}l6^I>m*P~DR(W&lfd59NiD#tdL(>=7vx$rySkX3PLq%|5ySAX-3Yr-r>vL(5?N^BN$&tejm+Ugu^RnTNaF?RIf^^tsb{m` z?>5+lyh&pQux#LYWnibxhWoa(Sf{KCdLFBQkc`y}fn=_Bkm3&cpX99Ymq-yTEjC1* ze?0Kg^&*WKz^ck*(xRmhI%WW?AcoeMD?wclW`K$rz^W0$5rE8rT`Wk1U@gohlhO!y zNs|%zA!dLcj(MNP5!@{))_6)HBrSnm%#tK#0IT4s!l+5Gd_~LvR=uan22Lr`m;o$E zT5-r1Z7R~30W1xt5#yCWwxz7wrdsuBe<4I@EUcITtn8%^mdiS7*sE@4>30A^+l(}3 z0INhV8Ym#1zs6Y`rZZ+j#$16V!O zk9`0V0=tkm;q8C1T3LdA6q=_{tpbXU8NdR*B8`-;BWcV4miAs91_-TiY0LoD`pKW* z!LA)?b3(i00sx35VoCW~@SH-4STO^bK)L^v#tdL7;kDpDF?+I@0W7!hnz&G+1oS*~ z%m7xdUO$&AO%^kN1$h%FgDi+NSDSB+0feee{(JPIo>>L?rK}9XeOFx_LZ+K21K-3Ms02vLt zpf`*ez+;$;Ha|K7JAqMC9$K}921$LpKtqu`}QZS#U)YzZ7fp-xlLK-uGRrWtO z06SeT(wG4($Y1UnzDuYO41~8?(00>PGo0MzMRhnGiD9C56y20~o!AoilN>lVQiUCW{%slHyE?LQCOe2IwIb zHkSXlbAAbDNWEYyP{s^kRgFszK+sjQH_mX}_-Rlk1YI{@i7DRkOCXiGF`pk4AFql3Rp1%SlM%33Lshu(wG4(C1kS$2wg$a zm;p=(kw8h2#SCDXLALvH$N|Ig?P9}Wl_h%<8Dz#*SQ;uqSQ*Pso_A4Yk;M#PLEMVU zq|9Dq*t=Jh!YYf~e7TfGsq2m3#9)=hjjUQH8p8@@#tdKqbC4ND0z~gY#|&TMV7+=aprNj~O6zxG?*w2L^hxbDs%^q{GD~ zlP--Jz?33rScFJo2Cxc}OVF)QDKP{B-(NMe)ZZ?btQU~Q3}9t1w;oDEHyLTn09L)^ z-X(_|F&s5U;blRz`2j*|A3disW&jgKrg>?bk;V*QsZRR~=1mZ!h#A0Ag081bkThlh z6C!ib>C%`1th{*$E?UT&B4z*+MZ7erAhX*q%gA_(Y~|x}fA)PSdM47bfl*wk)GNt*eN1+o_`u6-2scYyQ0Q zcWohm4s$J0b8%g4~Lf_U8-gA1_zOD*{{K|CIbCk&Dv#%H-l~5*c|EUNRPO_ z$~_+G8SnV>pZ`1m_RomTwR3pANlrYnAGu*;ZsUtJ5qKo}pPOR|rdLn@yK6_Jhu6D4 zCjsfvg25=Rd**F^XFjoa+Q2v+(&L^g7%`#2w3*0L%+nMPoxaa;DDj`LP5-LK+W|;B zhW*y`2+|FE^XEVRci-)|Soh^>N3Z*cbo)*86{=kR4%5B2-}a0bY{l(U-zj9a2DXVW z`M=8FUfDd6r+Rby%iTz;hi&+J{xAP~u-gkvAN>uTo>6*-_E$F^Q;ghoi`$kVKVkaB zL@`lDIR4TId9H4P*Cx#;(@jZR1zLo0b~HJy;=KDNTdezIGv<4?4E^5eF*NPBsed=P@P zU!&#=>mog7C-Wk*#4;tFk-t@E*(vd`anyJZ{-96Zwxil0-8Cb_e+kXYyf02~?pY9`FLed70cDYDK zYOuA~9DDg1(*85~H2ya}rv}qUpf9A)D(TVpJLKb2b2lnk=mOFno65!xM>=be67~5h zyC0q>Lmt>%pS3;R2kEYPN~bSGdSa28i=vPYnZxt)zlS=^#`GXE02H@J=U$$O$%y z#+>{}4;@SMn4)J*3Pyfcl%wQ)KWJYGJ~c9W&DsY@`#w=}@+li~k1okmUk7abI{@k4 z9sTDvM0)(hO7(w1dh(B^u0yAHxpKV}e>`|(!rsG3kCWIc&F{Q#9P(uE<#8|t=@!8> z&ymJ?&|egPIAd}ar0uuRJf>*(_z%e6v%svCi_7qQm9FoJt&DWTbH6>?g>)N<&9A7r z0Mm877( z9#izVX;YEkgFHKAZu=J0t-zlMUD$ri45WwM>$uw<^X+D`EhKq2L7ooTo*w)S=`ND` zs@J$dCI0%ZZJ8O6CH9Z*g#20j7L51~X{Y-#Ht|q$Cn}Bq{e41zTA_JyZ7(=Ji^qHE^eE8#GdOH1cXy27RtMYu44qrG{6KQP?f6qXq zJJqJIvn5BUFMk|Ssq^YdNcZ1L^O&NO_J8Zgp9^e3^VkinhUrx&^1q+ zY@`0{{1E9zABvv+TSyNm(0@A8fn-Wt+=f-pSBpPzB8!j3ZS2uInBK2}m<8|{MdbU`EzxCHpNr#N*wa^3@sR# zjP#UW3mqWf>yor3&j*9F!S=mE{>YtDP%i9D`* zm)0ty=g$ovy{KX@q^CvF{GUVDa$JL0yPkC%P9W{I|8uali@&VT^YyQ{C9NgW+28s! z>V|Z%M`^bdq&+2dZR+}aPW*!X!KBU`-_=5TdNG=R_Q5#3mb+veMf0?)R2O-Mjq&sQ z8R?MMG|$4W-VOQVsveQae2y={JHP$N-*D-^Uw%ZoRRYaFx&3TRuW^JN<4#PffmU${$DkRmHD3(gk%i4^98^rV{d0 zeOx5pLZtglt7BIU+d#lunm^|0U`%hji%zHM$-~|tPyJ#eLc1W{Wsjk04x}d)rulWJ zqA}gmolZAJzqm2KIe*T3?3%B9kS?&h$nJ_rcYQ`y+ z=FccS+UWxJJwYKfHtos{OrQRePWPVE2-5?T{#rR6=>hRH&(+hrTk^-HJ!T|?A>HP) z^iyctDCF-Z=@;nhha6thia-9!eZ(hMq{nU9^U=OFpI%qe_W#JT2Gd7wrmsWOu3erW z&x|NK{n;NY+VICy=F;h==p6%Z1@h;bec$_BL8L3(>-qa9q^BLdR&P1dwL1^0)fDNW z=<}3UetxqEjthHCr_bhny%^JrpbqG>JpD5NE#&caqtE7lu@KV>PovX6geA4-k3&1r z={*J&!1VsvgO0ZD$e){ep5~$HNG`7ESNyT(Lpq(N^N!B? zHGe#_ES+Agc~?yTYCN4@WYqL7{Bet>t51&Y%F|z&y#CR@UUlPn>b;_`lQ{MPriWo3 z>9b1uulVBK`P8-zgM-f?T>|@F{!9+T983>CH@xX0q?=yo+?f0H7cdq1hQ4yriEBOh z;}JM^qtEj6YWr-+Q={Xw1>dAev zp-8uipn1-YjluNDAUd6IY5n2j^>!JRLVY*1SWy3y!~dR2k3igL$f3 zQ~El4?UFEk)Yc<*5lELC+V027NLScQ^V9U{DHV{X3HlrQtdf4)rsfbnRo`i4u_H*= zME}a4Nt`kf>#vkSc?CWtrB65H>9D1Az)++IuN!Z;jdYKFrm%k;J~oU$S9HLy9deS@w(}&!8dHW>Z2WDLsI5Z9E z;`yROawFaMDSdrY^oy{@$X_xW&GWMKd2GY>6MoF2MY`hM>3{A;dP+x{-x9iUdJ^{2 zg;SqC?}_xxkBjaXLb~Pqfrc)@yo`~k1Es_wmAfNP#nI22Uq!lwC(Y?q+iwDY9KMuJ zUl^Y}kv|SQMW=W8v}Y23+~N+MzNgJJOwYNMPVZIjB#ups?V;0~ZPZ}D)zWwJ!Qx2Q zE3v;%Q>1IWr1?LGHgu^!jpu7p=1lL$Aw1pSH&fWeY}!!%T$RTa^Ztc&mmH?}^E+-q zo>pZ{@zCi-4X4BSXwBHh}9#(oa%9lHgw0~^u&(dR>F^2epzTiq&&^bkLq#}qxTOOJ5=-0X!kkEh#M zOdsq_rw`Q+#q{t>bh>NTo0#4ytMgyKAUz7(7SHLqs63|o7pAd~0z5E%#_6PPw`cL^ z^0?4EH2vzks>sv4%)N^vknUZK=4l$Zd^UeP$mDfs{(zR>MexU+A65~r~>%9SKyC3OmzG(Vn4u4$hCpvx6 zJCC{iao)Rhx_6ZF$+I=z_BpX)zvNX!hRtE0UuQGwbX3;5JBHJ$hUq=`E3c-Wvg-FCQ9MUy$@uEq(;YFr_FIpNosf3lRW3&`()sGsS6)#0 z{UZKYf3)STrAU{%`da%C>0tDKG)kSGGido@p2P8vwhdB|9@|JAr92zce&!NBwQsA^ z>GP5HeySVu0%`w*xkX1Kt&hC8#sTS;%am8+Q`)yWhdj<6G*9%Wud%NxHQjU2b)@Tm z)_5}Khgrzqq3-U2O^^=zb=&GEn2)JwJG4Ze9@@MJ@&uHK+c#@DpIQyaL`wekD-W&U zQ`=y_%^&&x@Cnn)#L=j4qsOh}k4L)E>1V?iMf1mvCAxa@OkjvSisjFBjc?TJ2GY$_+Wh$p=?Um#c&c?Yx4fKVyL?wMWdfpm7wP->5>~On-m|oejO#i+}=Xgl-(6m>(CTsa){}*&RO;_~# zh&-Af==87ixUJ)l%hsgRX}YY>V63y?rmGvKB0Y8!%`@L~6Q-lpf@6$Zx z|6GpgLEq5nG<|pAferkzU6tMiULZXt56wfCv-YZhxkvx zGUN!}HMu#`5lj0wh(KC*`=aLyqzmq$vBTphV|sS<8|#`j^!@6))O{bi(cJ~qWqr~6;F!+W{$+KQE0Bdy!e zwLwXwo#(e2IveTX*=a0IpDVNic{&Hv=`=m1S@s?LaUnxKmkLPNOs9EXHO+DY=WMhDmrv6=;L$mDZf!&}lc%Gov(ph4H!X$MeVaf2Gsiv{7h_ z;eXKSH2pa2CGt4tqtj_RUzW|tQ+&$6=L?bcl=$uSlTYpCF;$zE`gJ?fB}UWNq3Po< zJooX(gC+jtk6P;(hC}EDA;R1f86YYn^Re&r*#TFTMp?m^$(5PfwWg! z8v8l)tn;l8@O;&EG=HAjzaQj}+em!upr00Cx=;Mj$@7tR_oT5j-S4NT3H)(mA3EI> zUA0(204TLM?N3zZ=;tZJyX(G&VHBu5Rd6@(%;Ui z)gE~Y=WQIa7U^C;)3RvVeRjeT{&@7HKHZ8T-O`EXq3MU$Bax?A%CSCokMieAPo{Yi zu2jPGL6Wfn%~LKk>oNYgfCNkP&~*Rt-I2fD&Yt#_1Z+~Lb8C@qe|J@h9LIS~qh686 zdm~*B^-W)mr*oZ3M4qf~m1mVHLnpR7!Kd~}Q=a8h^7P$>Jo)bb`n)dEb_?2kI}B;> z`fmp0J;`&|`Fh-`-bha~Sx4tbw>ZV~_etjes{bZW_!aqcJz4*tEYg$Px35+h=~21Y z)_ae1QLIn(YyMo&6Zu{0jr=3zTb|qDC5_55c`&Ar%}u8->>7*dUymz!zys;7&1fE) zzFs5oG=DsF%asd*ke+}xMRW4>H#z=1!&AB3m1p^s-~L#OJXO%&^Xd6K+n(jAGP$-o z-$&YaXNA_yk#79k+H77(&+KOE`gD5P>ASzA zMtam^`Z}iQ5+nXb{+hE)@$7p1GxA8g&=u+4=Xp%7i4Q#ek)q|J2u6 z+I&J<|MTO?tuOF=KYCqcuJo-Jwnxt2`4&GR(vMPuV?w7_(`V?9F0-r>(>El=~% z^r7r?k*A4d>{q&C6HK2Tk$PnDT^`fANxDOQq$7IM*D*yW=6;X-jr%O?5Ot5|%m0k# z|Eu>LOmBidgFjpS)J;q;Gm7T_A*?W_hndtf&7c2|`*=?>=E?HBH;@kf_HEF9r0aIP zy7d6k|F5>QfQq7h+c@3G(kY$NB`Hfc3MeTZOLsTYNJHFfRu%SAQmBl z0)np?uUOv<`|#~}{(ty5e#h|~_BYpD&;4A_y|X*BE=Q%PkYl&v*%bC?*kc~7sRL6s=kvcKJYN9^u3=1Y~a3?AE}olwSf0=5wsf< zk)A9QgDLF3mfhE+v1u&t`t5yVj{M{dR_FZfJprp>e`*GAdKkfZiq)&B&w%Hcs0Zm+ zBF_T4Y0D`&idWcUe8y~bCjoE#f6&Mw|CLb$uYf;H0(Sxou7v4GBIGSynMx3!1Um?g&c)t zPyck_(HW#rxjv6obzHFq9WQTvqfrr~7=wb5`_Lw3Ex#a`E z9D1+2Ljjx7BFApUxzCiBvB%Lc{W|xG z#`iM72Y$7}JI3<2^8s1My?F|F@N|(ng`&_Y;=sf9o3q=jG2> zT@CaVyLTgo6X=nkPgs4cpW$bkzF?1~I!i0k0A>k8`VYT-^)Gfmk;j10WgW}G3`h@G zi#pIPC`Ozf0~RGfdXU^x`R_OEz6dE&H(p!>x`Q!N|Nk&`hS_)Qc*-hQZa=`XXRka9 z1gs@^my-i9;We#gH^4lRa(cW1FAYV>DqFr&xYrSscAkavyNoalU~nz(jhBhd%%giQTH^_If6KUkk49 zM;#%i!1|9)K#xRN&Vrw}O;&)I4Co~Y{sJ)=n;if#3D%R{iC{P@7@Gsn1#0HxA^1AP zV9S9S^gq{QQ^mvEU~szzpi=(cnCJa5j)L55BH|wdY4b3~J^h^5nxA zz*>&Mec0p!5Q93$h9Cype=x{!4DQdS2WC*G01Ywl6u{X)o`PQxgLM@;A{fpC{DrGH zy$H?&{6(!0gZf4AT%d==ry&MwEbfFDY#R*jk&fpDU637Gk zP)dXIms&v#<|++9=!khsVFq)R!p{Y$Stg0o%iy&GPZ^vI)GVuq7_9dMoDFzRC_oJA zoJhd=Pn19ma-M{9g0UyzY@0la<8n!eLCtbF1E^UJ&%4R1I6ei>3+kML=i1~iIIggQ z7(Blf@OlBCj=*_NPe2UnS8_oNGE^Qw=p_(?K2)|s4Ayl<2x2hrnRJN3w!xszna)iW z4{w7(oin45zR7U5P5y=BDrSg5ohm(q4)+K6t0EAddWb=`YIrRmTXh1?Uk$GXthag! zVo<+^2Ek|q2O#(~#Gq!)FNi^%S~%M#=ixlHs}O@cbsh*t%v%r73u@NGbAdYbaNj_- z`URY)0iFx!4e;7Q9~$6!!Ptfg95-@74C*%~AoL*|H^CXe*d{B8LCq#O&nBls4CZZu zvu*055QA;w?=L`|v&@hPJZB|09e8*fys5)$+4Sc@404`b#c}fih{3$gaDMRKa!v?h zF!o#k#GvLmM9ygyA&eKW?F_^1W0l^*!E`b>2Z2bZ;$k2wydD`GS z;I-EF3+F%Yi1VC>=LMP1*CX@^guV(fsDA;G=K`DuY#R*LcwuT&#lzcRFt%L?(!sjg ztsn;Tw!=9$J)H>80*)^-BUle&(Ep2wY?t6{VB28OpGzf>2J}X9t{NQ~!nIPG*Qf{muxSzq20UxsK4`oWOti0M2vS17eWvax2brg$81f;R+h( zxsnbs*fto9y)p`kn|?SanCq$|#K3bE&Ia@@Qk=g_0b+2TbPeG=-9k7|w-tiZ5uOEz zL4Ug8c|mWl!94+UU7LUyWa!~Sum{9oY)=Bt-!p~Kzu^4W(GY_*UJpR%oe+b0Z%9H6 zYTnR8up`7^?2SAGUq|pN#2{y{0)i7D25ae^!f_uOVlY>q6~v%^AKV{Mr*9OY|HAqE znGp#d(TZN_t97${@-r$_G?oQJ<%t z-bJ@dcUQ!&#$C^8XlOKP!e|<3UZR*$dZ=jBIn)bU6s-Ym6m2u@6dfI%4qYVOS-N-h ziu6JBHS`k<6b$MNAq>?FlZI+#pU7tOMy@h>-gMmYjBaWkujlmZ$8p#t>+PX$qe#)1ig7X)7mF$(Dm#R#Od9;UQkLn)ZJ>`2wMF~U|Mg2w3h>nR-i>Zr+h}DTr zic^WB#e>Cb#h*w}N~lTrOH@cakR*~+ko1;3B{?ZYC54s>mO3l-QhJxPhIFWOlk~I< zy^O9*f=sK-tSqCfzHFrIS=pCzv~n79L2@;6PvxoQ)#XFvo8_nW((TpR8@ab-?~DS2 zf}ujPLWjazMGi#^#SFzR#U&+9B{QWIrB0< zsUB6mp}MwDaG%Y-?0wz)R@HdbEYvd8y3|(C{OCjIbaW^BojSL=rFy1%xB99Euf}1G zT#a6hkDC0NwwgJbH#FC@1hwq6^0fN2K4}YUJ8Ktd4{5LKi0e4%6zUA>eASiFb z9nk%xC#-i^FIR6!Z(Uzp-%0G85bK58hR{}U;Bdj=jU&6`e#aw@7abRz z*qltAGM&1eR-JjBEu2%GFFU_+VR12XiFY~gGUv+XYT}yc+U7d#hH}$#3vsJ+n{=mg zN4tl)H@H8;?80bc5;5(Vc@I_(1CLmbR*zXvMo%5jFwa`g$6jP!Dqj9xXS~L|NxhZ5 z1HCJ~@B0w??Dg^Wsq%U3OXjQL8|qu{`_zxxPu(xXug-7MpUNNYAM9V{|1f|!Krz54 zpd#QwAa$U6U`SwH;8YM@kY-R=P(#qmV1{75;OOA?;8!6`AqF9_A&}-p<$u5 zp-;kgg=vI^hSi5nhtr4ahDU`rhtEbZM(9VxM|4IkM(&O@jm(Vfj$Do6iZYK%jk+AQ z6wMiJ6`dY^HF_~-cg(??~Y$h z;7zbj$Vli)SW4tcJd}7e@mk{hBYa0JkK`TcJMt+>ILSIGH>o%2W3o`PZE}8cfAZ%P zkrca>;*{Z(Z>bWg&Z$MIL#gX&;%S()<7p#lU(-d>?b7qo`_jKn1_ ziODR3{*}h@NC$g!`vYudsM_&(eV=uOb@QrH!5>^b@5fDRQwF^)rQaGAX2tGli%q`e zU&~}d&;3Z?Y^^XnsBD^roz z>54d`9A>}uKTVr@{ep_bay<6oo&JIwO&_1gCJXp?%Ed5qf4I4}cwLaW?sPPUmU_L1 zsMbUDGtor2R9naEryt@!`VlJ-F2yg%q}>h|-uLCZhNiw%!-MGl&+eXQ$9roZb*(G4 ztz4WDx%GKe8grC_kl-;7Iy<>VMkm>`bfNH2$vKQsqD>i>F89gOIoo04g~ch2qq`oB z^l$B z%Exyu4}93VPxaI0zj2+I``0)4YF2eXrc1=+r|!p^w#!!q_OvLhmPhP&*JO(SaF>Gd zP0pVE*X}z7@Lw)^pgq#=UGnbTtHLlnCJ`AWnoJ5S@&n=TSt|TZCfDHCtiLJHp40#U~gD*ob`R{MtQ9NeV(HroxJtmp|!4 zc={XlUuh^dccJcDc;k6bqrTTvq{kT%CDyDwyBGoq6KHHt% zCotwFYY}`;JocX!#h8fWzBdf0X06(odkMumGR&nEj8IQ8>rB)FE4H*JioLWjZ}(=6 zEYGFw4k(M-ZL4!%BJ$AK-474ml=>9N`^RS<;k;zx!5Jzf*qp)T{q6y2zD1$1^ITef zQeVb#xx9zNdPPlT-Y&G?PGNL}-z(Sb7O=guLRy5UvdaaZi2a@5qpRAJ8rcu1HI38% zrKx$1C!qIQ_~w$fq)YWh+r&x|b6Sgsi&rcfv`A9(O`*t$_g4sr$o=|+aBt%JG%wZF zv_~`3zPSz}+9v8_d9uWpq9!P=3_UL#H|SVq;3-PhW{@|(k`>QG*)*^H>Bmbx{zYAd zUcan*r_Q?`j+eDr%=$w`a}9HBhZM*<465w+>_Gt*=bUzNRc{yJpFM z2s1AqeJ=S>Pl>$rN_{)cTf4a)+$VFA@`6D1$-T**K|{mUHqQ%z_&%BblaNp5^ZvLl9^FYeC znflVmu1oE#N0$eyd=9hseQ#zu$(eHcM+qfQU;lemT~~H4*S>1`1Wivg(~GB+?{r@J zEf0iOKRelLA!ikLFp}eEW+Jy$M$A7+$F<*7kn$~YRXx*~y25_zqKj0&+qja7(G6xs zKDQc_)u)pgFaFVG3K42PuE{QF@G>~oAkV@(>*n~#G{eE><7xg}_+Amg?C3;)x@<8j zyPGq`WvV{Kjb8LZG@q0e$6rXbU;Oal@tpz`?UWZ%k5A{BV3tn3G&Eka#Td_02MIVfov}qsAHM*2#obO0P}z^-bb8p}&z(>#R)?7qJ!g zn4C4a*L>1VY2fUfDP^la^o8wH z{@q>{?I`5{3f-}7%ACKOvUEo&`-0Ie+oq)cyD9T`l=Au*x^CN)Ie+)O%-B)NUOsfw z)+vcTz<1#Th1k3B+28NNX^qu+Dmll=)Z~=*-PY_NW2$sA@YXTliIKS(d+lMtopP6J zvo|k}%@$PM=?-mi;+AFU6PwGpkLNvn+jzf)@QB!mfkoR~bjPJ{1M7{W_05sv=TA|J z6_%g2DmYMbdf2{+6z|tnwVzw3ggz`#|J`0D?x>eNspzV$Q$oFjLhhiK zS%2Eg=`DL{hUn$bAhq@FQr_KJ%Jx4@DfMd0l$MB;-=@?)Y@2dt=jGa;rd-%Er2``6 z4`H>>+od$wSuYF!H08{eDa{cnznZ8mZkuvvy?peiDPM1y(iV|&{kYo7b}8XY&kkNa zul_XU{FW*05Gns9Qk&l{C4A}GLCXF=O}X{^r8Oeur(m_0+ojCe*?C$0rzvN*?ByXu z%FkVDvjn+#b%bmLC3toJ_aA+EGEF5iu#u3FfDQV#N*nw-FZ}%!tBHoee#Z#Ka5vXb z1y>hOFLxz*jFLoPNa)7bS0n)#Oo%)5y%be83G~I2N2q6!AsrJwUN)IufSVWeO_y7d zp2kzXYeP?klESh%|9dg`3oQxP0AIMGC!rxHG~ScQWRc2~7(4cMgl*VXK|+K5z%Vkt zjbXIUH-|lCmI%w{`R`LYhJ*$LySpJ~W&O1=yoX_P_-zl)ux!39hQpB^p#>ufOwbcR Uv5lDicRZ9jOd^puu1Mm400qRD<^TWy literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/whoosh_index/_MAIN_38.toc b/djangoblog-yql(优化后)/whoosh_index/_MAIN_38.toc new file mode 100644 index 0000000000000000000000000000000000000000..c679078e59679d223a361f02b667755786fac9d2 GIT binary patch literal 2327 zcmah~TXz&i5Z>H3lK_DPL=mru6EABZM#LM2Krk*@F^Mo<)^RSq+Y@G{x2AityOF`5 z1UEVyZ{v$U#aADE^iSyF)qfCcdUhZuIUM(#oK)B4>#DA*Z~BY<+uMKrxxKypQ}0m! z-TfQAR+BQuX{qKA*XGKyMTuu9P?)?0JrVS(+EAfT&@(IaMbNKm!>F-W4ZqHGOTfS` zgoO(V3}W<91VvRVqOai_ZhM^sFr2$e4R?4+u;NDI+TEK0!GrE~wH3V*T;)({T!IUJ1OP-sec zE?7Wp81Kka=sOS+nAnm?7IQ<-*G0QQ;BW;4b`b9}i7B-k}p)R6_M)PKa?_VmuMSlR3syU5uwAcxE@ovt5i%hS850g0uvj zxc@j=6IU*3D+)Y^nVgK^c|^|b_uoBl30LNr*I?WcWVYKS1yl^2jNk=rAWc#bkHd>q zcuBQZ9by`#41{F=v31HEb$r6fj`qEb2&Fxj)*M%)oxaSPB(Mxl=A}Y`SI~Xxq3+9q zHFD2W=y^JVX;tQi&1-OY)zWn{L@3ACb)^=tb>ed(6qu>PYpRyM5-L47qot3|e0V(* z0yry;O~-ZN4XqE2Z5G0tQu3LAx1{75ZFpNogdE<<+=zg4GFDKB!@JUo!fY2$P&h9g z1tl<-Sp{5>s(ZiPhKo|N3?JsDu}R>P6wEffCowRQ02ZVUhyQ))|Ig1cl%6rhl&&&A3n%59Ii+xYOE3Xu$wJ{EonVisR7Fp)CdTyNC_7UK9bVkzu$qY8Cngl zNtG~d(6RvEhL5v4De>VG>1Pu7lx)IhOHh?g9;WemxhIp27U&g81Of3w&qN~lq7#~X z`t7lxL6v2kx4hd1cH4}=QoE~4yqXVo9_S(il^QI-nNpAnJOzl%E7e1-B4eDokNXXE zinBmB!C8V;xy6=&JjaoE;QHc~KSGmmlkTCIE9qXOgrR_onRpTSyEl^IMjp-+%J_mS zSB>C&TM#}c`9pyQ215jas_jc(-gQ}1XSEv6C3#Dl=O_?ikvAjwO5OX8^Voq9sk*Je z2729!;OpJ*_zk|}Fr7qRlSy)!7J=JabbJdrQz{+bCN1RZ%?=H>LNk=v={z*MAE!GJ ze5=xdDs?dPAhID)&OS;AsZ;$LB7 z;MaTUj^MAFsPRPi3u!T%Sf%VRoy5b}rk6?GBfdy}NhWV45xNe`9DTzhN!-6UyHH8u z0Z!_Uoy23-+RXaQs!6AO4?J?Zoy3E>giL5pJalb(E`@&pHKLm?v#z_2=ZK`d5s#v? zhu!8JCo(Dbp~CTTBuLkzCp6<>-DZ}>LQJWAC@$(Yafu*yQi+RcFdFQn6YtB)c8OmX zlqc~B&aI10PbVEu-2t&3D=jQ8cBvIjeU7YkGg-pw(t$|IH}UytUsgRG?AA<+@mMVg z=sGbh=7cl#Gv;bS6*}7WJ5b)BW92@2u#8F5L**Vi{zIac3qR5c{Ib!b^w`cTiVwTO ZYkJ{Xt96P^t&y7NPW{gnm4~8}(tmTE@;d+k literal 0 HcmV?d00001 diff --git a/djangoblog-yql(优化后)/whoosh_index/_MAIN_42.toc b/djangoblog-yql(优化后)/whoosh_index/_MAIN_42.toc new file mode 100644 index 0000000000000000000000000000000000000000..185fb97244d7f1353801215a3a1e4e4fa6687b60 GIT binary patch literal 2139 zcmZ`)S##V(5cU~+ILoZ$>0C$JnQB;g8)69?ni1luHnum~L^&m_{!wr1q@h6rqk z!y1(05-0HtHfm&TjlahA76J*cYhif9@yIY^N+2qtsnb_2JY-% z>+@Pv2ubS!BcU&iMURrmF`#E+9ePvfGp(VXo*ui@LVpSard30Uf6d{`!uAvl?m(D1 zXTTox9!g=@w1&~v;ZE4TL1L&?rdlGItSfPyaE3Z*%$!@QE(RC~FkQbl6rn^I@D8Wj>I?gC?!fBIAeXURosca0-u@ z^j>g^0Uu3VI@+OQn^Z&fVNQr~SYtev!s8Xj6J3laQ+R48#?xJlPKhyq7>cYaICA%K z$|f$Ix0Vce1~Yj!h362t(%*geswL8x5>Zn~rpTFYmkcn`aUzAI)?ksOB9Vk+4S3%4 zt})^|^%8`X|FLz(6lI)9vaNkDAVPgt(13-i==4R=BC+R4GOYy$yoly6{jd3=63xo; zWwd-Hg-KKAhRthAc-6CQH$f=IZQBT9af5J4lmW*Z@S17qm*#N7>c?uFn7~P^csR6+ z;FK2r_1kTDU7tLM!y8&nofQIaYG)8jy~aF!Wn(~`=<=f zYO_Sbls-5T&S_obwBfu)QiSG3VT zzup3?6t&?aeP9Yc);cZ}TqPUu$pSRAAYvRoo$W2p&MMgRnh0XTlgLFP_^gw-yZRl8 zxJivgoVTjm4tCp3!85z7N}_;+Upa=zK=r1Gai$EUg2(`(Yc1pu%xfRE%yGYAnc^(a z4PXm!O>eR1AkRr89=JYt>G#AX(xtm7=2Ed21z{KvVkS`veCI|A+{i;!LM2~F{`Y!L)FqY`At8be_##yzWqwwEZ>gPQAEL)IxMR5nQ% zGOR1P=5MWQBOhiST(rct#b<);x2ws