From 7ce4334d9cdbde1b98b7dc544489bc5bba46c1e9 Mon Sep 17 00:00:00 2001 From: Ward Peeters Date: Wed, 7 Feb 2018 22:10:22 +0100 Subject: [PATCH] new-audit(font-display): enforce font-display optional (#3831) * webfonts wasted time * Review changes * fix lint * Fix review changes * Fix eslint * Add gatherer test * Add audit tests * Added webfont smoketest * Remove debugger statements * Smokehouse: Convert save-assets-path to an array * fix smokehouse * Fix webfonts audit * change eslint-env to browser * nuke files * Fix regexes for fonts * comments and cleanup. * Review changes * Remove save-assets-path * Final nits * remove unnecessary parens * add learn more link * remove trailing space --- lighthouse-cli/test/fixtures/perf/fonts.html | 34 ++++ .../perf/lobster-two-v10-latin-700.woff2 | Bin 0 -> 47520 bytes .../perf/lobster-v20-latin-regular.woff2 | Bin 0 -> 33120 bytes .../test/smokehouse/perf/expectations.js | 15 ++ lighthouse-core/audits/font-display.js | 81 +++++++++ lighthouse-core/config/default.js | 3 + lighthouse-core/gather/gatherers/fonts.js | 157 ++++++++++++++++++ .../test/audits/font-display-test.js | 93 +++++++++++ .../test/gather/gatherers/fonts-test.js | 100 +++++++++++ 9 files changed, 483 insertions(+) create mode 100644 lighthouse-cli/test/fixtures/perf/fonts.html create mode 100644 lighthouse-cli/test/fixtures/perf/lobster-two-v10-latin-700.woff2 create mode 100644 lighthouse-cli/test/fixtures/perf/lobster-v20-latin-regular.woff2 create mode 100644 lighthouse-core/audits/font-display.js create mode 100644 lighthouse-core/gather/gatherers/fonts.js create mode 100644 lighthouse-core/test/audits/font-display-test.js create mode 100644 lighthouse-core/test/gather/gatherers/fonts-test.js diff --git a/lighthouse-cli/test/fixtures/perf/fonts.html b/lighthouse-cli/test/fixtures/perf/fonts.html new file mode 100644 index 000000000000..b4f294fc93a0 --- /dev/null +++ b/lighthouse-cli/test/fixtures/perf/fonts.html @@ -0,0 +1,34 @@ + + + + + + +

Let's load some sweet webfonts...

+

Let's load some sweet webfonts...

+

Some lovely text that uses the fallback font

+ + diff --git a/lighthouse-cli/test/fixtures/perf/lobster-two-v10-latin-700.woff2 b/lighthouse-cli/test/fixtures/perf/lobster-two-v10-latin-700.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..52bfe617773f146278e3878b6203a5013f3e2957 GIT binary patch literal 47520 zcmV)BK*PUxPew8T0RR910J)$55&!@I0`gP<0J%8;0RR9100000000000000000000 z0000Q6dQr87#xUV24EJ8U;uU6`}|U zz^s(c8cN1#H_O8?mLliOWiPArF5BU#YTcwLr%^(k=S?084NI7Vu+z#Ou<+$NW!?5N z+=O~z$RLkT(hq|Q#TXJ1aWbuYpL83HTdC&*y4><|raG2<)z1#(cKPp{xn_(ohpl`^Y9_dp|j|1LjB^&^^n z*FQBauM{d`;y0P-^$VWy!|Fiq8K)s3X-G58zj0auk@BiOq?^*~&!+gd9YH*s`xcg1b-0^G(y;l)(RCh@*fpQyR8UoUi z?mtf?eX5-^?1pgY?iaOV)5K*cb6MzhTjU73a|hk+4W=O=xlORUpJ2CiL^Xr5q}vA! zTnR}-V7l#KSOTRb4B-@SFmWU#_c#sV)y<&-lqKBPjijyG>!+f8Hk~&iKV@n-Pw%99 zaF`dv;QW1r;ZPPrx&;i}B@t-|GtHN0ScZh8T+~TY4Y&v%?UP%yGwoqmIwJJ~!hJso z&ng?vlhA3fr1ulZrdhIvX=!jQl5O{3^Hg-nhIl3z4HGOH!h3gufva)=nW-K@cfWvt zP48y;7j0MjPf^rEyZ;F}V*YAvEF3VhxqIP&ke zTiz{;HH;c#8?1qCREl7LieORNXd{>)+L(bInDwvyzJ-N>#h||K$=SO){#DV4>|$^Q z0~i47=?7uku&0nNoK24D$sX!fEo1py5o>!!W2})_!4(ch{)&n`_a}fcFBp_H1gD0q zy-c>{#gyrTN$}!Z?~2Y${%rm3b+qRiSfd@d!_AdtEqfCqh+#DZ3)of=FQB|w?mF|n zO1EfjGq?LfJ^w%69Np_fD2lZd@eV1c}_pS{y$6RUtg==z4KdVxkN>>sc-jA3tGuA~@vBb)s<2I5 z)V^~e;3XR3=9y~X!e7-;2fpd_?@$!~lx@he{I+MT&;^ew8yBd0e+$<^_frl2;KVbr zNOYqUB?`vc-kV`AxzP!+kNK*5g^LdngDEWvn5RXQ_WQ6e|IgQ1@)(;U$|H%09c;mf z6~!Q7(V8eq@vPIz_w8_hd;i~;00IB>eC)ZW88c=?g{CReD<{||WX+96QNl0j`{v%& zIL2c%_ccRL)i7rx8B=(KsZ+rPtvP(PpO!{=xB+EAEvFF4e^07MXeootBRHIVn@PDQ zx~GoloTbM$Ew-2i5efQu@qeIGBs*y(fNdaYd;3XmpXvO|PUMJZ1q)$W&~4}*VNyD! zrd8+HcKWBpW+%;G;H0&OKp(Tfq7Hsb;`!x$h;r^`{6sd;z(zg$#eTVXB0eU%*&-M< z{cr8uAF@fYo-9`ERPZ7?xO@?`YHr9KEIsy0jry|Bn>s(dHdbSXQ7|}`l);N)^3uGj z{oha$mKZxGJUN45f*I)-)88Fy-)|g_9F7eAX8HTqYYZ4yBoLx2*5`VRX?0%{1*S7} zquYv&L24`92by#{Mn~PN8aON-g6F?wzwE!%X`(7pZt@&d3pa%0adM`nhWU?onvm-k zWYsijX!4K-OcQhxk~J!&tdh_xtlpJt#QOigmfGCR$^NuFWxFlQ3Oi*Is>09wyui;3 zae;AZHbAO~$JdDJR$6qCdghk{q)4c&j4-lZ^(UQvwHk*PlcfXhfQxPkyIy{J6G=0c zov)y+?|`$E`Ta-ruJ4HLfcPy-AID>(} zP=ynYP4ten4?p* zBvRsq1i8Wk|9+-r%KIMcLG+Hnp>>>@^Jn(RK~_z%)n1p}Nd!DR0E7DY_#(Ty&yi}N z^0Jpn&bkml394d2rCBs;wzp*u9c@YGD0UV)21PHR+Iys)2@+2b`|nlN^*urbkTig< zu$@BPg?D5s{CQ~^jA5UOArK{tYFKx!G5x@8$N1)$TYRLZqYDRs+b zS#lZ1tt@Mx(k$H?+EflHhR`7B0ikfmT!K07Uv}d6da~Q3+wOrw`b$H|LNJ~&A_(IN zVT3X1@2JU|#UvE_BG?)V`gq;l?_CyIv9|PtGgh1gNEpJPFZXMHjID}HZ%<_i1qB>h z-T!NB741iq0Y+njCmY=Suv}S~wkP)8qmo^ZAsQeMBM_FEAS{@c)qsIrT+= zhl0VJw7oKQAc5&O<7Y;$&#hJLnhs@)wrZc(u;AGvII`1LBYP|a9wG|a8rmLuCiG^Q zH|!?706rex2wwr;2|onC41b77LcBusBFCV@k-aDpDjcOnIZ%11GSn>8Dzpea7Cjfe z5WODj#gH&sOf;qla{==T>&5oRZp5C$UdGsiyMLaitEFd;p_2p@QVp(0*@de z=m|-LG{R8A2*O0ddcs!17a#&i1(pHpfy=;S;42YJln{-?4B~iVBP9@SMj%l_Ht+;d z5?NeAR!&|)QCWpbQ`gX9vh)qu93!rkJx7kMUE;gU6|QlsJKXOHPkGMsUi6Z;e9O1} z05c9QZc#~Dc~wmveM2K>S8rduIew+;(yfQ4rBA;BgN6(nF>36QRjURytWiyBs^(U1 zy7_czwrUwdshKbW&?u}Nhzpj(%aIAmGU;-eGT91zj1ZMCRwz-dAl5pV9uw=QXKg~8 zo>3lHF;Fa6ERlv6BO{Ut>0+4**AoN(iobSh!guyB}FPG3#+nQ%wc&8>*8v4 zY^+bIV|U8IW{yT&M7kvDQOL`X&mpP+twH3c3SuFivH$B=PZXx1QYh;pbdiU^#9BsT zic&M8$HIhh$EhJjchU;S@uw7lWdI?;nkMMsmy+d@t)-7NlPUYw`CLMcd=rJHirK`3 zg?cR|mu3#b*fD5jC|#Cxf@A$i0c3t^;6@2^T(UZ&Q*jro)o4wkr} z%|#(vL1ZUZx9E2;7GYHm)Z$cFBB;|E4l6*FU=qA#$r{O|v}7O)@3VzOQo-JyBu7;f z7RPK%Qv&vNGAL?1s?~v!dW^Agzt(0EYUoqtA$7SnVZ#(|)C!gB!x!Y7RT335;61iN}ej#8{9{ag|lf;Zo`?Ev8r9I!Wo2}Z4 zx0Tfkx&2j+!pL#ez~V}^`qa`$7(2^qhuS^UP-4FNs|k~M!WR{c9gyUxb6GHa7@n-B zqiOdA@!yJcfyG5JmyjNnd#R89IZ9=twT{dyu(6Xwc3M%orB)}1&*q85QA#kN)WnVu zv@8ihAnd%Nm=J~=FNG9jF)dVsGD~-H`h$X)mX$b5ucc9Mp8)}_2de}Uf?;?V850*U zIT+4{f&%QQax}%tMnd0d;$YN8W|zdN47B(fqN8=020@ZE7{(|~#10vGu9D?wg4n_F z3o&j^yQF6`27I-g>RAL&$KPB1yev_`_!;+K$yThc*FpcRy)ix?xqSa9*i#ofB)0NHhOM`^t~67Zw82NSIzY>rjepWj6GzFKYuA3q7h$EFsqnDPU^s_a$6^> zMz9OLMj|Uh(E}-x5&t=~{7Xz9(d2|!cx?ifWJo59vm{uuBsrG6rUG4&Lu09HXlQGS zX>nQF`q~ECY!*k`h-Z)J$l4|6_!2HxaitwE$oiM8e{)q!gD8R=<rG@2IO5;%lVNV-ba9_JHsdPy6a_E*fsySAh`XDC|QA^9xJx`i+x5C{YUfrKLv zxJ1}Elvv3ef^~6(U!11%x{XFzLD;n3FRrxf_FT#nMzDzRI$a+ywfluKm3>_G?t07w9U17rXIRF{58+S)E%YN#vP zlYkN-7>AGyLW~WF`Thce<*7?SXd764Km@@rB}*imO1C1@P__oX{}WTb;D-}^`|AiN z+ib6G8~oHjk7(+3SmUS$S<_gNKwy*~ML)-2MY1OR z=wTtzf`*9L>kpcs)ylf1&d`(n!Oet+2~rhx!Rt55w;s`}b=M_EU2W^{MI*fqKH^Kz z<7pQd{ASig*8DB#e~W?CPM5!ZHu!c8DE3tp^LqYqg1`GQGkd~>sLAa#2%%6@P)n9L zk>Q~3QZwUKSIIaPW0Y4gU<4QfR58h1&UPtU;z?h6O}ScQJ2RZ?!c%>cw`EjrU5#}& z(9@`hjveOmlmRRui%t?%RYA{W@jx=5MH)+m2E80pnkc_`iKj&E=dxtxDy94eAtEBi zK-?d&+6is*T-;1RfFYt(%>Y4&`#1DpAgHUV94v-QRXSJcsfvqIckR(!g(gkX&{Th- zH@UDZeQc7unFkIAF%`2(#OB2dHcm3MLz{>bt1T5-1E6pS%-D|^LLOf_(8p8Pe9J&t z-IH@C>D(o1GUYKaV;&!bg^vGbcjNJU+fRx*$mj0<@BeHJXF6M(hd$nV)0%TS;Y-r; z3V=o#@e-mFR?7>}7~$ACO-Qu@-X&)U|B-3wlUr@RJb3cZR|NweSw8TzVdIUnPj>D} zHaCOyw@P$O;a#g(eUc;lDm=iko%mNzdTv|p2H5GZ9Asr0sK1YM-wx}B@BD>#`y}Hc zs?08nnM~)64~`Bvvu1wD;ygj%a}bnC#c_odg(zBzq}rK|ERI+QH?cpPS1$G~VENNw zZ*e>z6VA%n>FH(i!_y%_tSlE8sXYFl;^a$|KI5OC{K=N}wwj4cn}?vek2wHq5eClS z-2ealAAWn40W|yl6_p(F!UHszxTlWWs0d$ngJ;>Y2gc zefDPy$3C6{p-RTb*0a9Ic3fS~1%q30KqbL*`mMN{pWA0IsCHaMrMFpecZ&9_cd4CR zI3_Y=O7id*dhIw8N-mlODSwJ7E6Jf(b01_i=+4|RPZDZFpFZK~$;IJ;8O!%TWgbWn zj_{0wjb(9Y{r2scz)?6sEPE;lw;Sraq;A8Dj8bLoOE$!G1i{VFl(n*6lAiySZ8yfd`Zl;d zJNxw=`xGVA{T>i=~Pq6S>l;G;_)ib#AjdS;Qd+2Wb!cUR7cJSf{gnUWzj;< zZrg57gr<$y&%s(-vm7m@0} zJb(bXTp%l)KTGtM=ca7a)r=?uYc`mc;#L=2yMRb_$}oW3thvdVI5x6kLMp1kNhmxy z>R+;qKlBJt@m|VO_jc4vZuA;MtnA!rm)0OP!2BZ5e;vHl^YpXLZ_)hBbY>ZQQ8AwL zOn&#gvDtZYOT%z8HwG%_4+}R2b|j#asAN4;MDG=-Ijx>T_Wl23EkRi?Ma798POP#m zZ9|Vk(^vh>NVd+hX?Cr-^{`^~_m37CVUfkC_Grg3SWy*Wwy?C}9$&FjK*26sJ&|Al zu^$#{XoP-bCSsedN%`0oR)$4yL3i6lj*Lc3u*Owuwy%%=UwCZWgh5zXSfyIxik7wt zOZhXm`J*jf?GH>0t1OfesyAS0#nm1`k7ex&{l}V2r8y74|3C#4U}A&T#_AS5Mnu{4 zW&n?gVI|SR!YYx1ORM&Vyi`@FO8q9U8 z*afXnH9M-qx{8=8c$iT633M~>^%ZPx_8f~R_xL6x6*KC&Gnts3gDF}D3?F1lL06lj z4zlyp(OrT3;=s|5i6g0uv<>Y8yvaA z9o8Iqq){@}s*|n3c)2E-tWcvy#ip67pB4+1Yt^b!yLQ7ZvqF_MRS^yVksFG_3quot zWr)KwB~fK$(d6YZ6qPVlRk77IaCCI=^z`rz3b8pou zk9OYO<30EE0u0_Q7dH>rd(+Fupql3{fdXLp#uXu95n-4=A}S^>F$+h)nf%ddlg1d_ zt`lu=p+4vu)ei0TgVbp9YM~j10Y?A`B-@%ipZBd$XuAORY6czEx1|avcNx4|wk;SF z00C-xgAB`a_i}u{8 zEr+&jZ|RkrD`@8TdS>MkoK*p~`L@A8Y|+Oo0DvLtlxT11ZHAmmHY))DFkQCA?3l>q z7_hRV@$#*<$V1M7xq^LNEGaWmCW81I;md2fk z->^gggGrK0rxLD`u%`eNqgTSNM{C}{zniWx^sA6449=Cle}MPnlMn(34w^ugry|h8 z$ZNHX#HRQF<&CmPERK%!F5|dSAW3KmvE^5(z`~?=tvXOmfx!t#7OY@Mu)Arj^-*yGF zv%YI*4mKY$$D2=>vs=zxoXgrQm8(e@cqHx+ncN+@d6e5NI`tlu!H|Gg@8 z$GFEnl?^akfbP!pHiwysW`N~Kc4Lxb3%6qmKcoC11CW?yC^1T%>Dq0w-F`=%cF}eB z`Kx0r7L%1L2Y_)|vHKKa=J@>{NCuZG6-v4sXe9;!3{#0}r13zF8VOCeh)An8k=m^g zWxWjyHaWrQv~#jta6z7nF3VR)6vgL?m5`25KaHdL3uDIm)V(5jn{hetO+KR995s`- zB0b0gtti3_`AD^w>c!O7?5j}M&`T`y8`sLUbd4A4&g>O%SnjeEWH|3l9?FY&> z{terovFbnnm-?A{z|7oz7_6|c3@huZg}P_L!NJK{7gw5_n}>&&w?4jF0O02r5NJ@a zMo36lSVW{z(P}X_(B-^PX{8wlb;p-5zF+nrs^-rm8%(XmgSqGGX=lfjqL4I3OzU2fQ>O&-sd ztx~j-&)3nhZM!>mDlkkS!10E{a=Uiz*|TrI2M)?aBC*(^!*lcs>G#+%PMje3;nAmO ziI5AXRb zn;-}YiHKgzvPgoIl#J}`FfuYRy_vOS3079s`Zl(= zvuYf{$;rj_ZWiSUUS2-F_p^vV2nq@beVC<-gs7;P*vDC#L`X_XN!_$`s*H@Rteo8E zS&Bj^Dk>>`nRTQRs;X*gUuPX^gr=sJ*0)(xozT_Q(~C7R2tz|7qaU*lOv2RE%dp3tk8M*Ak~P%HH5)35&rSO*5fkRii{e}uJfG>ly;aR&GJU@}w5 zG#W74;9UQ0HgNIW!Jq zLd>_1@__yQKm03L=K-wqJ@rq&9@iZ%3&8VOFIc>SK|IXo}-$R953pNFYUWeaZT@rS6t(Bzwj1G*Me`CT}4_ogU2x5H-M9#t9}0p9(d)S4*V0y z)CoTUTQ1`&Y7EeI5DR#<=` z$g6VjesJ7$0001t-&;BWIT7=GOcL<86gKiBG$J5~zLEfYk3fuA(ZARp!zLh;$Hp0b z?U=FzLx!$}Z8qqC#;|-hOZQav)GgoFYR) zB&S4)vOoDgx5Es-5G(OdY`d;_0J&n(t#C@@{n&E<;_}erP51Vhm*bzBn%3hMY@>da zqz6f)PU-mfs#Zeb6v{%f!0RO{%I9+BRJ0+D^WSf2i4U!mV`ZYdO1#Whwr}|A#t^OR;4Qd)Ijj6_)#?)$j4p29&ZisAQt8U=H8Kdkt_3VCFtQ(W} zSRf^oRFWhSwAY~y0p9Fa9KkFYC?zt2irUv#+PC^LOTlo0R-tgTX$uwa7US~RT#lov z-?_VqP({Qdq6k2=dpb>cgU>zwjW;Y$z!M_gwMx1Cjv=pa2Uw2~kmo4WZA&#|1H))( z?wV2*Ai}PHSYi3C3xO}jax3Pyu6morp8rLOcf6_Gj@0SdcaCH}AjB42p9SWxrwH`2 zw9zHqKA1bcTiXeySvI)CegKd{AlTCq*@{KRyZSmQytC=IP@y5MIKFjGx0oWne8{vLB_N$<2$SMeTBo6R4Umj4BGzU15Ltbo?R%hJ& zSky^s16iXMkfb;#{D?fPP1JfVqq^;p%y;{5q_BxX%j05yO73|&@k$?b^#*He$l@scb z{NBsF)N(XY|4Mk>Mp%$E@XD}L0ZI}QmykGVe<3QP)frtrajUU(cnhDBBp;oOiU9XtNRO1Z7K45JFP>bcwSncqrLUtAi{p=gshJ6p$gZ&k52FFvGOc3;PZ}`a{`oVw(8;SR{E7tTU z3x5J0@>&t7^qa?eM>z(c&UR4lnPUoP+unVFo{yEe`x2z^=E91V#rKqEIkd&c@e$Wa zV^{1|W1_r~QI;}v_)!ER2>#*lDw7ap{+|{L=9>d~JL`Y?M1y10ubLfQ?9JSjCA^X&j1W*6I%`w4cBfIq=;*ZDq`>>9|F}7sus%WyC}c=X~#ag8w;cF z=ktm5eNe#UuySULrr7Hw>p@UyZZ9sPqZPanTR`f>5~yVwGjFcL&Unegpro|<;%3Z9 zmauCMq4eMg(iAR+o!jPoO#R6`wbd;=GF7!*EBOkIJU$VV7L(&eaDEhCIdV+gQ=+0qY+?oqb2KO%q|iPB}=`wi*-C zNf7AaUU6`~j?+FD&f2N__ig05YJ=rq6T9J8u*@oT4okdS;>Z|L(s>b%#GD8y2FnHJF9;ML!<+QO96(XJx-4eu=~nn(HgLk63VX{LIpQU0J5Z{(8^u3Q9*1%!wy#wiI>JDnKDEEM zFlE7`HsjVdxuq9{fY`sy$5#U0tW){{R>8iqbhv~pHtm9TzW%qnhGA_o>7Eeu|J1=4 z92!WQ+mpgEqAx3S$#K5?y8Zg)+_J1tzn(Ig9W|_Xj!*0)JBNlonl0=<>vaJ@_;E zY`~{k$QEIM)wmc{cI|!9kT(~HJwknTx0~Nh7q=4N7HZQL6toqMhf+xLV#~{^+>$te zKG#kzM;TCXK`tl@*%*doCM*9c zoD10R`P=a_2%`2(?};my$LM%)f1TL-FSSoouFWjMXu_Of%BA0Ty{$5D1#(AT5L}u9 zGF^(Q?HgP0t{k-Fjwb=5jMJo;%vB@jDg|%U@hLCGhWWnloK+EHmWd3xmaq*sB>C=l zHJ3H9zRXFT-){VE(K5ZIqDClvYFy^43qnafOR5|$-YA@QSbl%u6mW6zy`>_i_Wr^L z%ZB>*&Erej9fKzpRk}Ua-Js%1Og1s#mzq9W4*!42yH!`l4~8iXYwd*)_gQ+BkPC zgInZkovG_7!ow!1C13lJrp2}Th(_&QcDFIR?Vc(k${AwDthB88wYvQ(?_@|kXNsyT zbfrq*NvDP>#l8_qz_zFm>EW_SW4+&9$Q?DwoarpJTQ82~p8Y((c)9{J>&+t1^v;cx zjmyg*seBt1`N{+CNlHAHOtD;p#5x~h$bWbzBJ3;b0W+zRRLlu5<>d5~Hk^~_@Kl9>`E%rh185<;bV(vY)$ZAG;_s1;qrbsSr=3nLw z3-D?C4^orX_>g|C!#3kNR`QF zv*onQvv{~-K}*2yc4_@7Cj>~YmNUTgninUV@A}yzlF%ijs}RYoR$(g2Ij;_clA>+N zO8LW~+VHWTX|i#DAnciU%Bevx=cxApqV!AK?4Ej+=C*;zDFE|iXf8H8TJAuC80xFX z918)}47!Ad-`>zPBstc2mHP3R$z8U-Gm2$z^kv;H|>l}htNN)PawlUns{2L2YV*iwQ6oOxxz4ZdF#1>a0|4D`0HWr0m5^3*&)LHxta#k1*0XYNqwPD+T( zK1bYz&Z8!bm3}TX-N*M#O!%T!D_F(NJ4;u3R!Ss0XF8jeA;2{czr?-a`_h^Wv$C1} z|5~?m8wC|X!nz0+Xo_~bO>tr(vJfD2BB=%2yVUXPawKvtLZA4yh-2|Xq)&*IBCMZEUSKnTLq?Z>2UEw7cGIiLm4w4FoglLs7ZIWtklGGgb7XrCQj zR@>JO`i)LZ+%1}vJZnn&B~aP@D3dR8UujqoNrD1J^?NMbD=kfz-#9tNCu!Qo=(g!f zRU4n3--P&jA}6yy9YLbhrU!`P*(sHW&$L}U5;D85YT$SRd#id`e*%%|ym6 zHRt%J4DGzC@oFjwf&w$TJ64i60SINl@P}H=J_hr**x21^%W6iui@0LnxXnrb@>RHal>g)pCHl~vU_w*uq7 zDvFgjyu=erl3HphY)rO{iabB&umU}S7m52#s37G;lBM>U*ipend3}_@cBI*8Yw!%y z8;k*9+XG{Vvp$icFuM^};w559;NqWsMi8vynQ1E+^+n5yDpfEGVJVsM6HqB*b;mp$ zDl&#bR+;v8!=SdV934@Y*9O9U#@_E+XrjEV6ySdJ87LIWeks(uN)=wkPi<_n5G?2$ zt85!H?%DPA!IM5q*rN{K-1~U|L7ioEjX45+tc~7ST^oK7zLN7@OB{K1Ihh%bZ8l!Q zA!Nr{gJ{eg$a;Nj!R~}$3?*=_c>azp!wi60`md6mbUH~&B$&CQGM2r?A+%n1xRgJ6$q0YOU}XR%Lknqfx3}xjv%c;hMzL`?abzYUOVyWY z4UkPj+~sFlA(oHOy6Z;X61@SIib+vY$Aq%4h)X*V@6@r13u$9}04{Tm9OWo#C0%eji z%T861&@l`*DrZIV0?PE;+gc&~Sl_vcztisAwv{8Go>ynnSH@N?nCG3j9FTLZEl%{( z5U|d~R_Jc%Ut!_qoWFgsST*J?H*QjEih>WcNN@$HlxeG>A??}??k)hoVM&m_(FQYy zPNS9@-+hV=iA|n#m#DP8*3&&jn2Q8Jlb9mW^C)&_zUItX@2XD-BJMM{NXb_y`z;X# zYQGM3wznX#sb_`6}#0!-KYgp|jl4w1_@4)&VAxiDsh& z5u%<#BLW(G8)LCl%Df0zXb7keY4uK8y{RHv5>%kpE;n#hRreMR(1bi`5lD?zT#a7o ztIE;X2-rcksTomav$dtM4*eFatx7IecOd}+`O!<7je=HiBsJa2jz-}=VE`hs9r=HV zcur=se+KCLa+FYnDhSCI$_A`DX$7akl9#|mcnCRA5%x=~Go%-d+eK!+;HyjGy)@qJ z_zJt%qYTHLje6R$E+=6ECH=prZ?9xjF2#Fr%gw6s8*XP_U-I!JD-=t%s4v#=8!5g?h7TKcEoLLKi^3XSbq&N8Mp{9Ar~rQKVRn#d5y-7 zU_!S<|FfuNk!%Q@`Q=h^l$#R z{`|r;jeKvp_lWyHQGE&^%9A~_J>gr9kV}uOY?RB3=PBIQW=i5CrM!l!fu@=UkPcza?&K?No@8+GUIe_81oSLOC?OB0dguy?4L$s41;@G z1JVk(4DiyC*wQ{dFF zr)@kcG+6Z(l_n$8G)k0c$Yq^)%#{dS&UOC{1QLZJY^KohNfT-1DalQxDgv<$UINl) z?B>csTW(Bf8S6iixM{08DM^(r-#BxQLyPYc*7(cg zu2^?Hp$;iCGx=CvbN6y)SRXd!l|jwr6*M*IcwSDj1Yo*KeVW|#1V5eU4xb}Yn!-S-q z^K&)PTH_}=f;QynGm&ELzn93CM59N>O0mXO^1Ql{#3YU_ERUWQ9>-$Ga!SK4=rtL# z3Z{ww5X25j94RF}!&dAc6~20v2ynhj5yYv?)K(sya&_Np9^%aDXu+e!NbwyiZn^C$ ziMvYQTke)c=(43|k6@(JCaAS%S7`0x6#Rcf7hq`!GFtOu z$^9Qh&Fxq$s9*qkcA^qND5>Ki$E*bUw1YeNjiW+aFfRStQeZ}wG+$oCQ4_~R2g5_C z*Eh5?I2Nv5l zR3{ymgB^lx(LQNmohUdl(|y8rV%N%d?`J*x{H5ReI~tFHQ@d%W&0;n|7a{z< zBgUkS*6H&K6UU1k*`s5urOYYLa6~>WOPq4h$Bk5Hu`NzfZJr+AARTPAMxf^Vw`vI; zu0|tc?3eEqlWznO&RD)p_xGlSJGf28%0;QEXY_2znN1)gN=_fKTsS_^(YK->0(qJb z;pb)I@S;WDgrCo8ppAR%SNQpsqM$4-yjYWYx!z{hq%jSN+)8gGFh*LIWY$v0NP;Mu z4Eim;Q%RpNxi%=OJ4O+ao|jNBw1=Ju)kH*HN;9f+NJHbI$fLCbyzayHX(dv)Gv;d= zQ_ZrI@{whCqld^wIkWWr^C*#BpG!3<_=)mxktY|Wb~_I$!6 zABZ{)&?Ek+)$!30GP^m_r8MhhPJQ;syfSR#jQM__bqL3U-Z**QVx*!||3JW|hoSmKlA+*F65n(rgrb0gBiM8boL zl(8v+_Sm$>g*2w7oSdX1gi=GWG8cziHAXg$;~0I3B(6`uTO^o3J`6pu8iaNy+NO_x zmWU8E&u`=I*fqT`7+hf?GCu@Da?$pGE(aOy2D>u(I2i}=9Wk?TUjA7sZYG+>ns*n? zE9NGV$Iai=6HkojaZmSfOJIMg*~Cec%b31cQ;sN(v16VpTa+3pSi=2NIi?shcln)n zsiT&MaCH)bUBDxlOmj=dU%&GX(o1}akr|LekqKEMB|iOg6JRT}vT8OSk2F~IX0bYs2e>otu-Qa*eF%o8pfXY{5T`{Yxj*l=d%8nf1E0^v{4lEps+!>T@it#Rs<$ zgM5d&-Vebw;>>GHC)%Kd#&WyRP|9ecdC}n32?s_+EFM#%bOuLZ1ijhpS~1F+4lEb1jD0j|wz>D@PNKw^c$jsar`J z5IDK;e}BV8Q=KJ|{We#5-!#)X_k^q*vyxO2?sG&$pm(=t_|*M^3XagwG)XeT!HxV? zu@Hf(5bmV-YudLm^vLOGnO3u;sRDSbJdaae5DN~&{gco`v}8>(kvQJ@Wp_hNQ^wt{ zveX|5&>dj-1&T~HP?e}Dx=QOOoJPv#?DpzDwoPgu6dx~jt5H?HpKP7(q&)YXZ};QW z>*NXo_OvD#86uAos?0{#j^t$KJ6_+6acw(~Au%~1qZ7pMZ1;ks(??yDGl<}jQa6s$ zK_IypxMTHd8u8frP~W6UNMO2YNJkO+TE|&p(h`JdU4rV`N1F^KpsMY>7=pkfM`KK) zeY$Q)71N9vZPPi-dCPe9up%<3>Ub^l1Zfay9^ePeiLOR#Px*2GRGwr$(Ct%>bSY}>Z&WMbR4Z6`M~ zd+&43t*4&upWpgcRad?BR(G%43}*qu)E(o~+*-r9SwL9kG!xN4eX$H%@E~3NRS7Jk zP|k3P4xFm*e4|x~Vp2ArZ2RDaKVz(Zt)Nl?35e9gEgC5mmaZYY0cV|;=>3A3qlZ+gslv(|^K;P^@;%8{LUfz>L(jm# zV&L2M;P4&XTsGWZhQO}~2`fyUkak`0`nrfLzg{;^zry#&eHa%tK9$pl=t3 zPVhDM(|Wbv!9#Qmor8n2i1H-v0rvxqcj}nn_^Lgjm`I4zr)18@r-+Q*X3w{1v+#Ao zFDe4;VdQX8iZ*mmm~1DzZ{2}m3Pq(UO4uN&i&XJT zCFX5F`A7N8eV{&QLh7ZNWo&TGCM189gYZIelvnG+LoT9Ntn(1r@|hgrCPJWbe-D1( z-G?NF#1l^(WD!8n>R|QA?~$&0Nnh8T_1YgWxK1PaEkp|frWdQd%cWN=rs##M->6*9 z;hf$mJrs%|y*DtNU~}lhICZ&Y-t2MDoEnk zn+5jP{`L}EV|R2VDgStORBP+fb>PI=s^hY0-+JZXizMc@QArpRpOzH|yyTDf(t5kn+u? z(3`1ZncBrx{u`QcO2Z|{nO>culO5j509gTOAe}$qj^1xy(e2XM=XE&GemGHW)a7_5 z1u7?6sfNy>L4;di$5?wjK6poChE=-ha>whAUxF7o>BxJ;;t)h5;qj(^Yn?waGP#p^ z?{r!ci@t^g3N@mL4w=^!8rOa^fBh&I<2 zYRz^^;lNer8{G|^b=EGKQW*0=45l7}PYtIcP$E*qb=`JG!Z2$2Py6q0+j`(n3>?$p z2~Xzcg_PjmBi@Cr5!;IVdd(JVJ?a_Oh`Q2zMGoXaWoGVnz+nr&R`0F2x)&n}`g9 zhI8eK#&V@W|`d(LAVGWJt`}j6l|hS+}hrO zq7qKfSACEc5IF&?MC>?@gp}K{j;h2Txvq+Li!`<&rS%IUj04q}Tk)R_YWy>p>*LtX zHdPwEc|~FDjr`ZP6{`1P)R7oC_(0=HXXNvsS9}{)!?$YaLgao}+zf^Y3Do>bDpwU`tM7ts&+x+jWhHM4`-+$nD^^I{p%7s469FGH9JA%3S}mH0(_ zB?33beFtmNJK4IS!0MTUH6o{7^??0|p8A3HiG+NoX=Iri<&+-HQqzPPi&01aQ%;qU{Lw-llE|djBv?z_GFurA z$|)K>>v6^OSgs|PJCi2;S|d7bGhar*HkDPnP&q*o=YfVrGmB?VNQ{g{Y?<4SO+>#n znnoJ+8fVD4LW?Y@*XZ-s_~M6a^`2Z!5qR7cX&++vG73w(dGk7sWM3Oa zKP1epaK1(4loKYQ7)?j_IHJ5$4i6RnY{-Z>KNB`u{!-zvU5*L#!&I%l%v8n|bEjkY zjrEv&fAe}zyVj<72ccBj$NTo_PgFyaT~pEb!-VWXGF$q)Xji1vG4V8={(O^tk@>rLPK?3fc3kzxO9JF zHH0N}nh;o2SfGG*@MYBy0!3*#1aKt>s*U$LX|m)`T`78V-P_Yr3nNa=4i zAS$-LnK&P!4*4 zAcQckpw8>srONDpbmkk)upY-zpojAr5L_Bq_T1&cP)1q$EZ**|p@6R}C#K+W3ZoL8 znq%sx(T=r$>a&8)8zZh#6O=Q=xz<#kA=s;-Te0Ai0<-8~x20dR1mkGmr@X%9Y3gm{ z8zj#j=o*3tYurM*50N{878QJeuCGkRd9AJ$AxXx~mHU37Ec^0W!n?ECIcrX0wiH99 zuF(l${6Kw;P{M#S(W!b|EPt0c<=Q}3fL=2(h5{Jy3ANuyL_dEH4lIL4d%=Sid{s}c z+8bJAWxD#0te=8CJToxWez-~Ly+OPq7Lr|5>l5ZX9SJ)w(u1@a_NT;jqR__jb4ncJ08hLLPGSf#X^~^%;hv()m6!$DL^NZSPD3OMJPDDn4MBX4wlC|j7h)IvCFf}I!xW<*m?(&-capcfUJNl~&NLL!Od^s9(a3_rP9j7w7EFJkAQK4u zmCgsRTCj6m8(c?w^ml_%?a47%LqZBK3>{xLx;ZxiS8XOxOlliv^Vt}yiDJ+DNEUI% zk0U^Pbu@*3ecMp&84`6yFk2Ws)0tj5AsvyLnHo#=AZ>s;f@C zSmjQ!eiM^HwKbC~7Sg%Vw@(J+!&yrU&s5Tt zu`%V*?y;jjkCcE@!S!^wZUZeb;@TBvBP82mpVwmmgQcg4Xp19UD214@ve2{+V@9%Q zN;|zb^kxA>ZSq5-HdxO|pKaU)>@7NV(jYZ{GNqElNdJc}V{lhNjy>JwLz*9p{OL(s zV!tPPGmlPMtUi_R`KTBK3U6-JoVZM_1Qk+B_cVjG<=#BqKu5?;HVJC!p&`H8a!hKN z5$T#q7fN@&J&^txMJL0<;QR3;oG~y9gYX(Pzu`a>Y*)K-%Sg;j2oJIHTY%2-F9L$@ z5Q?y}C>)m+-Ok@M#@~39XbNv$$l0*`t3g~P-7+3UDh`vl)9sV`Mi@uLghG*$m=QXR z#d1}q?abyTW1?Vm3UBMSh!cIH8O?xv0jfeYg<7;BLPy}08y_?#_v}KHstibAS3-Jl=|{;`DjfO6qgo`S3dVsC>!crfa*L4x!?nz30Gyu&U!#yNe+eF1 zOPCaC^I~}dQ}vJ8kAi%{??ZyWf&IO6`H`D2axamYNxO$Y<{TgVGMLr9`Kb*#1=0e( zD)q4_NVmEDF$<2?9i}*_TA8a%-A$4DMbc!kdzSLoucux$Uf{&Zg; zp`{%4DpP+~i28x8pXil_r31jeV1S~V;?l0?N&js^3KqhDcaS6g&Od)o^_S>Yos8uB z?hG=6BqdBu3BLCnx+N{SU?3c}E(I@fc)Ns>lxwCiPZn#@ks)P^Yap5MW<`qvmOwfl z2ucj9X^{2vE_x3#DRi6J*gc@V1U0)GH--QY31gFoWe8de3c`aa3>Or5_cOTcWzGTD zJXKqgzk#A+-a1FFF_V*QUx@xd&S?-30zXv0|KXKbUS1^`aCn+&7}|1sKx;0yw^Wxw z3^^$dQJ)L`S51RGWn0RCB|_T#ItG0UZxCYnD&;eS~R*`{E|23i8u$he* zUKZzt1Z!>q!d39kJJB{%%&jd7wPO`~5Zh4b#$~d~(NSF*nNkYp)+gp48IqX1-C|L( z-NVq`lyW>XE@fewfKnv2jh9Ehlo)a0ZWCQCoNz^NplwZ;sYSI;%46lJK1}n@m9BK{ z>WjOek!8%_9oWUssv27Eokfc$_Bk^>)iXOo-WwOZlpdNGp%7t2iDX*RDcYtvg4MMM zd;TA#WA&!D;?GBV{8){lwF00$*-ZYpk({?H^9W zy~Bep=wrc<3W$Oj>`|B*7OeWQ3oqi{O*ryG37>3!{UY@2Sy%u-wVfedntYYH;fdkS zdnyUU^juli_ki9VAJ{HoRXGRPOXmWu&SMdAw_Hn~AFpRzHZ$DTvENhBY(Ps&v`!*; z02A58H}TjZ)@fK?cI(PrHf#@1AgW)U%7&roFb}L_wN&ZVnLu!o+yg*dEo?FZ4j@C$ zc`dQe426sw7y%R(AA-^;c#sdH>%-^Gd#7UTlDk%RCE_9)hE_a}pzToE8bZ{;jIYUg z9}pkmd90<)t8J)Twy}CGmYxk8Ia?FFWyq7$d2=Bok2p8tQT0HSrS!vWri)LUNg7q} z%BN9|4}X6iJTRX@)+W3*aoThkV)%Vhbha^kuS3jZk9y*((1`FTXAE7F1&oJ&zChH(ozS!?%AI?HzY#xgb8ux| zg9l#d>@YC>P!qiWuwFbrr7FC#AN6joe;FQDjbErmJC{9eXgJstg8_(4lLK5rl#J!= zU=|$9!GOiqNCZsqI!3_y<$I9e24?UhiuO1!_tvpm7(Hr)9Z}-h!Aklf4i;=YA_fGX z&G($VQ(@B6nK3eWEZO+ZbWo>>%zj{FNdcn>U0sJoQ1~3NrVrTuK#hZ*_Y@svN~_W; zlW{+aD;t=PW=PSgRL#hIL8=09zjj*v@9-p=M!f>>PC@u+;wV^{jXwba1-i4<-&eC> zC{s*}gy`$S<@swk$A2)m{<5-x0Ei$$+Ip1a3G$ld|5zV92?T@4JRrX>V-K`!T z-aZuFYKz}QA{I>s&7rb=-JIglJ8v>VclZUnM?Nia-x14*nG{(hk7gHC)cSw&uwrk} znguCGd9toCtZmHO*QC(EO2OIZ=}*>oqF!j_<;#yg9%+77t9h6O)HLkW59IcUhvGoR zDNfrr0}{lkvzW&J8fy}sy23ouRc!aun(KCrYv`jP6^gmbno(y(Gn4yOA^wSR{^Kfc zw{5gRWUVcd6N@s2pQSEh9L6{l@dgtU-kd_e%i@A3zlx|h)0ihe`qcwsnF0tg|1=-O z^uf5m7CwQvFnaEA`z+I`d@wn!7tf2bE3~NGNFgMQqq^BXYoO8NzE=lSRHA_Vsqk*? z#rUqGu(C~#=Wt4YEEinfEDq9^aI|A3hhLu(d!?Tcikb4PjG&74kR0(p<@X(PmA0)4}0rlycz~=4Z0(PN!l|r7EuQ|nw)K9qSL$_J*wl^JA zaImF8(Atld(G3(VGB4%3K;JICO7O9(iP*%a3ccOiPd|4v-e`=Fu5QR?;QZg=vf7^1 zy;s?z7|M+uIU@q@5|bwC_`_;FJd}CmwWz43;q5M&1-tBnb%%VxLsFQL+j!9=q{zX- zIE~_up%v^Aee)A|%}^d}viLhM^cjr-z3TTRcW{WwDi=QauTSQDJK%MO#y;{2x z+K4>1HD7P}GG5qPdfMbTvjJhqL|ghNxA z8@n*$GmO)W2(eD&d++zd{gc}7X6!-f2pI1bV0mjfzlODlp0_o>r5Hikcc1HFh44Hi z^j6N$OKSs{P3cZ1V1pWj5*Wc-A|%9N!2Z~WCvM$r+@z)dE|+dn&f^eKx7mg^UvR z%{h9fx94+-EHYaY;*oo=btH7c@|8Ksdr4?feVe$@N4I3-7w*srI80U7**9p9>pXzL z!ZWDen#9J-f?EKE-P;B_BQo{irRCo_wa}7^7a$wQMZ^G49H%^`w$TI%yM@Edw#cnJ z2hgPyqX-itkxd69yEaWb1rmwF28<{_ZZkiDHGdG3>Ejc{yRCXIi%%{Wv=5mApZjghg>f49E z+H6KCAG;;0bM0I$ifM3COT*DmyjF|fAM`ETOh8o2S^#K0g#a-^sj^0)#u@J3xKOSI zqM>j@_=t)Ha^W-(!SNmKM+SVyS?KVdd%vq9C9(Pl>K>sEklaJ@lHcAU!Dj=K4*KAJ zDiW0pum+K^u;md6WEavW2{<`4N~#HrfD7eFf9D09ogDRRh+ZIvZMzHMB?pSZ-=KY4 zTBBaF$0(y$U%;*X{0z#Ly1u>vv$Co0fP*Db)U#2+sD2h!V|2>TzG_OGf97n0mUR8) zXa0y(9$Lw<i^n27ew?bu4>qc*bf3GpeuGdog+qoPIPU zsd7XM5fEQWXg|FSt#Y z*cNd>w}J|eBNs?N`ewMqr#)}ikf4!Y6+~CH_>TN$V2>w?w~StRcCe6!z84i>EfZ#orFkPt}cslPSgdVhleG1RXaHwM>NyWNkA%4 z@13&o2(X~#7f&5-5(`UBJ)u0^FbK4<2Klfq$X<7(&C`{@F)=&u>ew}c$n*S}_~QAK zB!;};Ch_DhzG>qO3aCfl>o?_S!e9?VQghGumlz9)s|D9s#^Xak!H?Opi!ea-b@vNv zZen2C=UY0e%>sC@k4`XSAn?5sV6V`kP6W6PNmN}{TO?K$-vqM786&3$q{zDSTW9im8mkDDfhc&>q& zctgbPd$lN`#XEZ~It0u9ga)y%%Y4)AMr)Kh?Mh1+;g;XI<6b7{JWvn@zZYE#Xztqu zzIvj460dhacP-qjXzke}e^Y}7K22^rGKO_u=Gb_wsoLDif?X$mDFcIEk7IfK=w_W= z5tZN2OE`Z$=WezryFR6V!#+XJzUa`18MSz|BFclcpDY@AO(eKdM1kL$yi_8n?QuQF zkqOS7GQ-T?2ladSZ4so!$8oCIS{K&URzJyi{B+L7 zno2R?{1(yD^+mLqT{&VTl~x8wSX~FJc#MK^UrTLzaj>s~ldxgI1odv)u>P6I^tV!_ zR6i)X&5i@KdQQe|_g*mdya$<9#Zb*3Z|L-@W?!n}gN!+n!5&19!dd6hiC464U~p8@ zRIklL={P8KbG9e$bijFD`mad$ltdeQ;DGty?ofO)IrS`Ire|wa3n$iCtEqutUGVJB zA6KLKX{roNmd>mdn2w+y)|*%O_mij$H@t)Q^%X^RB<-mst)(3qUm_hky+ynF@qDx1 zKE2f+zr#GYvVFrs2itY9IbcP#wHk0mJ2Xmnw%HhbMmzkOuCx6Ha_G$(b2woBgn~(v zj6E`KUU-Eg=T4&=Bd~w%--kVe2?s~cz)UKM}HkIvZy4fNKkjnlZPhO4c+$AiTe~*nb__ z#%EUU{Us^lESYu0@sls)HLG-h;%;cCw>M9{oN9;P9<{+L^m95KZd7f%56vK)ZX)5e zwPDSA#J2hah4PS9?N;T$;&x_!_kl4ZXQM8TAw}E42yG}XHNQ>?8WIcrwzxu>N!lY z>agvZzuLI#UU%S^_jw z#R@Efo+r7)&`e&OtRVhth*1B5F6##@`tQ~Jzktys?a2N74JZ`42pavbNC=HIXS5FJ z%Ug_Wpt=YaNkOlqta@*`9zzaO%DCpA1K;^V&YQW+zx7%!rQ>ifEis2wbZ$Av8*)vq;K_x5k&;>ZcN=5nKQ~0QP zt$aCwT_J9m_qc{cqN{Mb{NK=TbVL!`z+WDlp+%$V{XNJC=_U9Xr(Gr(m61(KYvkg@ z3*<`_$rJueaup|`iv6xCat;R0yEUobT3c({S}<$fRl+|pE3NP{D6`E+D;Zp z>i8Ew^q_>(*pY@OPdTWmD@ZRbbT35j6$C9=E%NVl>v^0ha}*fqHp`W)oDqieMwNi0 zc~LqSR4x=yH>UmLVx)t6&crLIxrW5#^=o!r?xeu4W&58R#)`!nf-3dUxfl+ce_ury zP7~F>*gYZ5>J)&Vc&?}n5}PkWIgMDnvwgT_0re9~wJK*-*cO(BD&VAeOVN~dpNf;t z3hHv;l*)B7gkm;uDWxPavCmtQq=)|VnExoDy>2lnP97j#aHt{pm{+~xn_3}cf`8w(py&^25DYHrfZvo`xNu8nb8Yp47f#*y!WYPX{oX_X zepk91hVlLMjt2wq$jL)%5Zm2ouejJK0uE_M%F3?rRjw zbBcw1@!yT-tXU4ySgKD+{ybJXE!Nj{3w*@h)f+2Ey4cJDhc+ZgRwye&#U_-_?4vcwe}Zee41G{B02IE4YCRN`H;V~szhj=rMQOJ`A1OB znA^NK4%_l8n!DIRnge@c0L7zvV2(A2 z8nPjLCBC)+Ogea|uh19|F63sYXxEnmecZgyXDdjGsIf_=2mtejGOZP$<1-{-!X z`N}CJ1m=I;jCPo?m)1xQmrgpIZs1Sc9zfe2!YtF{HCD`FgAzMZ?{A^?h0Q?pC@0?+ zs?{DGB$!+aTJpb@l}8eiLrOqGR$?g8%UM*H;5bhj>p8e0#-hd+-~PDrT>7yAV!z~n zR;JeSYkPk`2V4gD05;wpX_fK_%|9TrplWgm@bM+jM^85patsvr$mWpC@E4H zXnoxSs9m6FXno&`e=@O(3ME_c^?ln^hh6QjJlM#k+=-!A%(1ScoX9?BTIk>8Pp@Iw zFZYxe>+B#1atUf&%E3*2tWpJ|TX?9}UG=dIm9KXZwqwc!OQ@(m<@SwCvxuN7aJwj< zWu`f*YgA!k^1G$~KU7u1F>+If7_S`FhlCUQEoWrLBXbHP)P?Y>^*j>11lX zo;l$^JucU;noZ8v$;4vwE%1Sq*f=EU(sDV55;ch^XByWOvSF3+D{ zIm>CUsO{cR>l;|F7aInNc)^+4;pD`l9a9pE`^2bUF;5f#U(r8Eug_H3vU{+v|S46SaPr;NC;ZCmgmWT2^K&MLqT4CW=iyXglK8KtR_^l zYw^-DjDVSGESUP;XPLhS*Kf|oquV+OV8yhp%&;JJ@n3VTSzdn;!t)k%TKiEVz*XWrf5i2NvwG+qa*Nx|lX2PwaAWHR>(44{ zZm`-(Q}PbUkz|ZKkvSpu1H?g94{w!m`Naer!~2S;8L9Ak0bfo^0XI6T0M0%1)yn)t zFAlImO2RKo^70dRy5}ShVNIRUn}pj=uo-*}aU>>ZYO->`?3D8J3wV=n1lC_ml@dM7 zX+fH+XLXRxZEO_Vf}@g5190}Tm~-Ys2t8E=(>2+GYZw7SNyBFtblX&6;kZqo9;Ag2 z@NbIz0uh4g`*M+zG`1%{X?W|G$>$_AI zjT`x7q1eH^i4HWiX2e(LfY4-rgA5cN@Bpi=e)u=8VdT}mvchZNqAe=hOH=!;Gy{2e zhw%n<{vR5vO@U_wYey+IpDs<={xGUS%G|>?=>7O@iU@#mw(*{r37raXje3)+b-=I;k6fxm^a5aDGNlogmCx!P7Ml^Nz0Y=N#s$5B28fv@W~rSK()iKp^Ez7{A8gi?Qi zQJDhPOCYulyq#tHQ?c-W-2jd2Pbda3w0F1GQ=XCa)%7;Rr%WQ9Bv}Mb1^TD3WR58qm+SHpn!Z_`u zwsyKqSlyB1f|ZLwnl(6x!Bee(H+hn+YC&CMOTHUM9Ji?vzWVb_$j!dI23=G{>M8lIZ!S*5* zWTDbJ1(73im5!;kGm@+<5ALkV!`tV7r{TlREv|Fx4o|Q44KtC@mOAc4sQLInIVdZ; z7ES7;(f!0Qoti9z-DDPb;or{6ab;cdQ=-R@>nSrs!mJTRc9rsNm6%#?$=aiHBQzu+ zXPvW?3ThGPFj2byB|XGI00K_ojDK%!#_koXP*O`+|ek3DpZXKTh0P*jlkDlTK zGcn2$DZVv5)xMiu_~^wZguO3*U>JP+i*ZVG=jwIH!2u@oLSl+9gOlRLI)HMYj5$-hETglHEd2^p#S04-GL9I{p zPbmqgbnfFh)vt%zH5JR7Hf8+!whJUt-34EfhM`(|LCy}fRwF%%EcInXdR+73#s0FV zNIuw;&i~0I&4hD=8Jz?qrXbLy#Tx4DE#Asnp*ZSCTfu`mF8Tg9!jFvPuxmPsU8Ytz z3*W?2j84WPu^U=HbLv(k7D2C}(WZ;f0hR_8r>ti&DpqMjwUa%3V%S{E!ibI>d}%m_-7?e#-Yj6XAh^aK0hfc(;<9=-{0t)^KhvcS z&aaL-r=QX|eptYVIO12`3lO@Qy+brQrOlnGF>1+~-Z5n&z$dGqYk~*aw8(pHw1wcr z|C?$A#pIOuQ*SaeTEx=+1D^)Nv2=+E>k@0)V@8W5WvS)*kD6}r%6VvE-tc6lRO*v1 z#dqItSs!nDomWxdcSI{qi!)@mJ5|<)u)x50gbCQ{ejq4+z^Oz7`|3`Nc^U8)$tZEm znri=!eT-pb&yX(qW8w(mFH4I_uxDt`m>o*0wP$QRG&XgdTmDyjA%t1e6b|(tqjWQz z!K1bVA6SK%4+_}M=erm{Qq2tZil1d)@O5B(IF%Q0nC8!OhEkE(j!y{)75LMYrw#r} zxQsgyKG~KVdv>>H-FwtNqY6M>ZBL#{p;d76$~DdXQ%n4-#49E)!b25tY->psLm%t}hHFp`HIne!z(g><;=DsK;|b%<=5 zhlT@zI2!^#4ovkGD7t3zi_4}uD@Wyq^!?2|tBHrgPSS+SPN412x$lODFo*mr?3T3w zEY^n-1hD&IMsQXpO>RR_o7xJ(NXs>yfdUVgwin;d!i z#Q&)n42E-+1`&QPFq<%5t4BSM&9eg5o=pW1!hbdmFE3z%4rd+y%PEqu2ku^@vz$G3k^4Uf7Fg#) zSRG77CX+O%-(QmBpDEms(65_RK&n)+V5|mrP&Zx@dSD=(It?vc{4lR>hp1NW31V^0C`jq8;r>rZ1VGYVZ{Z^Uzvlbe#iSBx zrlUl=jMjvh=4wfa8o71qH6s?WZzs-^@!l@ATqV)^93jX(BvJ}KJ?d;82p>@ z3Get!Y%2<|b^ie{_+JnPzG70wsdzdN03dRg_0N-v#s>l%<)N@~BUW(7_%8zUHCLV@ zd}Y5~FhmlbU0^cd=lxR!1J<~*&;$5k3mDjX#Jn1*5LFE2DqL*z0{gM#Z-W#By z(wXtAZ76^!CSa7g5o?waiUDhnPJJ8KD8l?YMfyz*U8>n$%y6ep_R<`ZcTU=0JI_wk zG~)k1*(2u^i}5C(wS_45b=8jZ#7G~)-qgKH+Ln!s@xNfGljyu9hIf}xh01Dj+xXf` zwaBL9>${DB01)txI`fqB$yA%`yx^nlnjX)1@j6ta0c|di5OUZ+5i{q%W>l>~eUbir z0EG9S?||SMsJeU!y6rgbilB;c;SnL04_xJDeHna1-(<@jAoRWVbrEYJh>n z8lWHsvG(iNsQv+Te@y=I+#89W?F3=|;50Wfl+$WeeFH?HJ{X~6cioBB zyoF}On-}Uc?unz$>{1(ad|EEvHz-5qSuOsYLwF&7YGF}AjI8??o4ZtyeY-Q$JlM)I|)Bo%I>|Gz*0& z*XFd)#VyCknnH7W`u4!5NQ%NisI#$V1|Sg#@-Op)WDB?tv*x0|+&dW(WDqi`Sco8g zj3^=9wx@lkTwAb$QwEBX&a^1RFuc-3`02w|$S!N-uFGD{gm9Euy=R~b=$Dfb0`$YW zmzvZl6sF!Kv10nD9>u!`vi%&a9%AmivjO<}2j`LBcJ9IXKEqyfd!y*|jGt~^qew89 zfzs~FDTu`6DTSHMr6dvlM28StLl*}dNq)xP%y~v^RQJ#OV{H4si1rk(l5lJ{b)ELu z99u?pa9`t@ToHlP!j4v#wi1p61 zLU(h~m1xBOU>u>)-xRCZls})yeZE=>z`?wOMV|I~PBtd$QLoA^n2K*$EaNhqqo#|) zU9z+BAa~C8{WBPEHtzEZ43;>O8_9&MQ=T%;Y^@BoYm??aRV`Xhwoi6x?W^bf1LVw* z7CkD>$x#FCeD5`Vf0#Z>`iR})1%$p)$^DaDZwR>}I*~=F|L`X;pDaHF-}e)6%y56e zl-mnfng4RrSCYE!yB^cZP_@&ts_k%UtPd?cich)zZbvY3oJoGBpsD46T1QG+?IljFZW&#ow!SS)d{x01}686@VuQaJ#?pCLM0cv^II zpQ`52Y~qXH`l`_XjJtiq2?KWuw@;B#`dxf&c|C|cV=9#B9cQEbM>_^QQ6~}U-R2KF zxL$M5rheg`%|+VblTmy}kvBtTjkrEsN;~OTN-$nMbgMV8WsujUq8$r)tgdFAbag#k z6+wQNQmbZ|`+MV}#WII_jcNNM! zt^E2Ekx3(QS~?#CVZ?c^b^AJXD&=TggL(&&Mu#&s^RGuN9@~pnKn_{(TfAF6y$r;DLb?WHa0_6ZO%5G6USQ@#q^yH*q8oUaX`(5YA_8`_W6>N2M-ga zC!f7TO##;0GBw_Wl}$gcQx9%2!u-rO$I&pcR6BTKbIBw4y$$8gFe0_ql!!PIXSOW<$@4-3!q;cnA)m;{cc&B{f>6)<3P166xC48-{3s!dyKL`{_2Cm8!pe z?Zod#gcvHe&X3Qj*(Qe{?NjR&-Oxu1x_8-W5SFeL_HQ{u6gG0+BNl4ERa@D=qpiP5 zyZDSx2b=1Zg}^(eloGo)-b0NQ1a0%mhD7`&fgxGw^JV2T6egZ$qV^Ob4xaY2cF$6B>jic#kq{Y}f$ zsq8}mL(}o#NBY8jPjJGKUEMN>YNQOB(f4a>(c#epw)>Ig^?a?1hTF>(8NDTlq-6lL zgBQgux3Gk)44RQc?SZfTSkq5I#Sin?@o2it`-*8bv0^Qp>RB!p%>mLf&P+!am-MQ_ zT5$EhNc;aZR@66mC&$hwd=%j=;JJI5a>s$csjLy-85;&$`ymEW>V#b{V40y7o{fV z@#py{XV_LfP}9+}0T@=fY?Dak4ubuICjQlKU_{_<5aI8NsezHJ?d{3`7ZZ*s7Rr~5 z?Oe{Mn>|J6Eu`8zsr^?be8m|A3Fux(xR>@-ILEJEmar|5gQJ29OWAy`@!K-)Zg9?1 z13l-1#Qb%#yDj*&^m~HHi`G0npt*=p7UsHnKpDfRmxkRRtRWd2E?=Y&&{A=Dz|Fs_ zzZ*0)qkix2;KqLgCeBGW;KhxyeijWsMuOe1|I57J-ky!mN%{gN_J7{uUl!U`S;I{# zYS>iqHEEs))>{5gW12tbZ;s^GgH#|5*Yi-!gpD!9yAF&|wTzPNC`$9HsPyYGx+Cw$ znv+sOG&0d+#os6XA~L@Cj0+o?|2(F>U|pv7!0n*U0;NM_t&7eAW&^mSen2X;(gMQ$IUxKm`LD;i?XTAiUK}|AT?<_y^e3|;{7LYnLilpZ?S%$lLyJ}? zd=E4XYUGChi`C@VZ{H2adaDS+X2%G23pNDaXgtnxn)LlBIB*FXKI+2D?=Lu_2D{mC zszB~H>esOw@@{+U1fsvltQ1P4+T?BOq9hy~o$ZBv(2P?!%OBlfK@Z55E)P`h+P?Fu z&tZNC;svWnAqNjsHF4v{e@f}JeB>Poqfn}+mS(E|Jp0Qgf1P{FJRpak1A9pI zH52TlII}j-<}~+??G(C#%pm)0g2go7CKTlQGozdUN=kI&O+4mLj)G%zngPyG=fnge z%6Mxbg%qxP_+*1{*SM65?zvp(T1(cQP9#~zYkPDZ1$aQf{jW)nplfDPl=Ls5790{1 ztR|D1=?839bQV~N1IJG=z^@2wLC5t@#QoZF%=s@zm@Z;6t?w1-%{owH1zhPAL%v|- z)@{UMDVBZ_)Jl;KPU=K=BPPi;)o~WchsN5;Z+p0gaQJl^we*4Vj6G&`@%)7)^KRE( z?BV}df>4Y&Wl!2K+3=gAV>|A6n<`BIVj*d1TKu!jh;x#(oJK598$xi~A8~JO8*Gbs zY**>9HYi+pW;|=$_)f^bZ$qT1^{j{eqVhPd?7UtjQ2|=AAep=<7=Lea>5Mqfb!ac3 zW(Bow*AX+ov;gmn>FBmJj!O2&b>l`O$hN7hJR7awqw?ju`&K?itaiKpUj98oeDY?n1Zq$5QMtBlLE)J7a51mumZ^ zb!v4BX`XdX3UVp@Sy%YTp{n5PtrZvk;8V}oJMNJpc&f*0MLHQIL(k&d8Z33)>x(wj zsG{IIe|XrxaR!2@?^$fQ2|u%luvA_w;cLeM(ceB8V*%Yh5%0h2f;Scd&bHphBz{yZ zfz=dG9f}k(AN+)!K@BByBQyml4MY~ge!T0V$=E1YQSOh3At$Knm6R~u!;<2(>^I(* z%C_eoeV7;cl{2BhmW)=4=CW6_6)XRbi~RW=gkWChiUucl9$Gkd`Ytpj6&k=J{NLRC zuWN!rw7uUXjlDQ@dpBIu_BZ<8>L>G_pb`M4`X>QLSL@1A_=r49P3Cn^fgmOC-y_Tu zt1b>Y-k#3X5;Msz)R#4b<8iRmEKfO|D@RnBYXP&pMR>NX@bdDLX?g~D^XTzU z6Qwe=-ZpIJU%OA#VL7jU1Bsi>Pho1*}5Q&NlG5!3Xyr! z^t9AUSz?1Og6~+i3ih`J4m(wEX<_f6zoXdZ*)?SuR@alfem;*_F1nNUnk4_Bd*AkM z^JE++J07~C^t2a4Ou3iNkoBYNC3brKLy&t9ZlFp2&l(rS|LXr$e?L=qO+9oY`wwx& z6HAGkCF;@~R;9j^)gNZyU6WwX;#Gg{w-2M&L!oDk?=_xdDt?Y<)tlohV zYkt0Mr=-Y1CXN*gSg#qEvfc&ERF)5TOO=G)jHjbrym1c%d=>uc>p6&ZGO@ewrp}W7~Eb z+s+-^Xl$dgZ8x@k$8KyJchWSrtv8RpzjxMIGyk8Nb!PAD`s}^GhS(4Y`pP6%Ptlym zXnV7aR$7|bzq#>QKayhse^0I-F*+yn9O`19ap^KXDA23a+>qPzJgzaUn%)-APYN~& zUY>fKfen}>c8mXBg}{w zMMLCS4${p_1g|j%oC|Cn+~z0;KhsoyvobL2FGZHO;S%zTgMqm9 ziKmJ!%?cq0gse3_AKtumPG&)4GSKdc2{eV?5ephTwqKq7sJDxmdMR@P1~+*vUP0Jn z1+C6mnQtye$af|U-uS)WlEfY6aha(Ti65S=;N_M(xErm@d*A}6i!~PSPHLcf2- zZq8qd)fiR_6uJ`uX?$0Q0c8VRPLCw(2et(F22jow`2!n2QT(?PDRBmKN(KLxjDv;a zBUB7_wrZeLmSx)KL-LMSEUdOX&ueaEjN%bw4i>TUv!{4@ZtA-NqPH6l@fEXJG9zaE za-o_A8HO(?8M7pxesR4Ekb56e=F|^)B}jN7{ZTHVo!d0UDGE77{c1rt;asg~vkt7S zWg8Ev87Q8O%`RTd!DZ*xvD3Tv`p%pobwK}{yv4(pJ*FJ94}iqvBPt_?7j^ug^LTSc zqpWJ@-7&c|7W+Ug(wbju(smL{f3T72*p-#c=Vp@2JTXt-_(@s~cJVWY8E5vjXUXpY z0ea(1f(QySBkAbv$nwBKQ{HWRF0bC(NjZwecDIfAVJxUWEtoA|o*xOY4HkcNE?0Q& z#7$wgD%VL|zdG>D3vhS!F2AxKbs^gf6Ez_t1D)k(eNGV?zg$lCE#6y-zTH8+!V-?k z@U*ln`=qZet-c*qSM3nFcUEsXWJthe>%WjSVqK^HX6Lzpl5Ndkjg8lvHJq4-OmB2z zOM}-!!aMs2M&ihVcF;@Dl8oWxwd5i<>ffm4#0HOXZAz=Fv$uC=X0I12rK9A;S#A{m zi9=Ap0KZ;G;oL-PN@ZX>hf}383&!3jM~fC46WYJbI zjaj;o)!*U@0u}HWdf&!sbExMrel|LKG8!RxpYx^xq^<6`Cn%+;I*i&bd8fl%nQ3{q z#r;wLRb?G^&Qs{sLaw4FH<^isg8C`4*N={cQDuj#opY#=|DtKa_T97h6ZZ>ho~j=$ ziRQ-PQ*?2mH=N3>Cnm>gmp$_KunBl8Exytg*0J+n-t9mBMCY{K(^CJ?BL7}3J1v9B z-|M@7_lmd~nD`RBv>h(Q?(=55y7zu5Z|daxO`A|Y>~zLXwl=d-t<@(+@rOw}HE%Sd z`9T|N-|l{X%-(4_0^Y8%!9=T06>-ptka{k1Hv7obsujdk@S;JtTyVEg^rN98x+kbY zrA#Ys7M$uRTf=It?;NE><5^to$msg8B|(3VLvD*qpoGcU+`JMi2s8fxH2Xmx1{$C7 zZr{#ph!3a6=r_IQtQBGZyDv;Be=!1=iD9AyUzAk!G!GDVO!T{A3?mfFB?Bq~($PSD4K&B+G|X+q%R%IdKtJN-4TNik86-f!g=l zli9vGjVS{m{FOpU3Weq2Lvbp{(3^S5OCVMYLb}!s)4SmsPDOTh1pcJL7?6c!c~ESe z9Ap;oWevmKmxy3wC;Xs9$C8$X)zdsQ8Vo3guV zb0@8}n#Av2f$&eC&O1(5QRX=i?pmffd*rg@yM(S%g60rR%~PpZZ$Db3_wyb7zk()4 zq;jU==H=SRr?w6d-VrDhJ6>^0zIIKN{lML=g)#|ARPn=4UE!xo>WU46iY24PRkS-Q zyv?&U^)HyQ3VX$}3Fw6QftqcbJ9%w(6y`s=eOdYsu=GJPV(iwQHAL-=<51Qn43J1A z{G+7OY8hCw**qnI`EdGGZD7|lOjW$w(G}8vVccNL zxA{E-ulxVmW|?o~gYoa{r3;@qgX%D2Rf(G`+82Ev{n6^rxG$P$wy5Zs+wz@0P`O#@cdy$Y_q^k^ zFZyn3P<%7QW$5U<6I3f6N_?y|{KV<;JeVvW-l$N|Mg(%TO=$UwIVO5s{YNspm#u0Z9! zWO-9HH6Xj3DH;G0=!)%m^R>_5(9A& zvVYBRK#-;7)QKqYHdnch!(_tFf+CP2;Xk81pEInS^M#=TA0sJwV!44NCo=W(Y$yO5 z*RdIO&_g;B+6D1ax!CYvwh=J&K>GF5kaCD(hTInw#4^%rTXt6d#>>?Wp@LH4p_fi} z=f&LowIDgiJd!E>Hzt9^D(urPMj9&V%FbtOHEpP`;#RbINql;XA{riWi9;$HRDVm^ zpWBcqvO6V6V{Wg>+x4|0bS zF|gR5QoBPco7>C*U^nX&8C(F3)m~8KF#l#;&|t&xr`(PMe0D1*lOH^{zQFZTSt2Lq zqhx&*@r!P5dE#>abJr$^M_1I|QE(toz`wB^!Z2$$Og3I?Pxrl$ARSF+#O;WnRAK%} z`6l2cuG;Ma%-eQ;SI@=CPrX(XTda_P7Cs@1jnw9aq?Oukm8MPnDJ~DdcgDKc6Y_O^ zHYT#9;WHFczo2Kv=bGwzbbqvrSPZ(3+NrWA0c)LDvFw-*w)qP~=ky>l1sP1ET7p?})KoPdp#hz$b8$GT`0vU z3<~NODKZ|hJI5bLW{E6tr{>t}px*x5fBENk%9+inr^0ahdv)lPuKo(>m-w*URVidN zMp-w{{7c%jLc)Q%84!9z^=h#Wv14ef_n@h!NyjXsSohtduEI}Q^xJvZcJGc_B8A+s z>Ukhv{V~mF>aWZhVQ)&Yj7QG#JsVblI#quP;C@qZo;*8+zd8j~V?h;C>VYDvEVkBs z7u3uFGt=CTPZPr1a9m!Sf^C78h;x65ZP4tN(ob$)^!YwZ1CF#GtdmG0FDB=zF+Rx! z5hq;rIGPkvP9-7s`Sq8wblAVP$o79-azU+L7Fp`dc)PF3;t3RJzZsW)A_x&$(Nf&_#sa?| z!^Vs^6$2fMI*?^skR;|p$#N*J0i>oz^Q#QhH&nLKx_)pIz%{I8s)AtJP%$KshVeJk} zsYW>hA&!}Mpa}+g8;{>MURIAA0+O;Vh43w1cOKw}v;t zDSDwU34NM?v;3Q*eNSWBuusnTu`0Jqk#-`NhD?YgVNoDyWr!zk?v1OAsz3IL-WRyp z;dn%}89-`U+JN~I{Rv8v(Ug@p|@OTu5>*4i?-}+ z-3*%U9lg7vz*KY{rT33k!%3}+o&ep_WwYkx9hc<&&GP~umDeH>7TU}XkHjRe7$w@S z1~fBjORlzAKcH`6x#AHrDUMBQQB)!_P=oCnq|LHMX&d8HQKZ_7+|sQpJGU5B?R0xo zlBzXv4x2=U7a!kVb_Yj;cdT!AFa<|++BIG+YIX{m7QC#1K6HcwwUdrAs8l#>UE1p%pU*Gn-~;(^nbe=;sEeOPS{u%Qj}yzA!PRd>R@QSkORf z2Uqr7(BQ)f-Nqv^JnqPA}4V=m|WT4bFE_&E%Y;eamC{O7VZh%Lo4wo^P(!^o?hrG0UpsUal3) z?vL_w_h{-a)XvcYX=o;oJZm1jHUr@nwR^XRDV$zH=t@p--1||ciD?<-6?k$p^4Hog+q?2hjIBCA6V#(cYd+nfCkex% zKS@qYMqJ&Jtz-UhE$5|4lo--t~-uTzYr8N6?5w4VyD*@P;&h+)u+M9dwAVT-maUj#udi!fbtc`3Ic;N-A1Fvbh`ob5J}Y@%6EsChUyIV(?I`qN1*Qel zZXyiMBcZ;*M+O?4Xt~u_DV5w8?fXf?Af<{tPt|`=;3__Is2Lo6rKi0?PbpzTLtPN1 zQva04Xe}Gy<1Py1Ga5?N|0^-`OzC^F7gP!gTfh?}wXt*!g{2iPv~nDocTSA``54mK z9*Zo@!jEOV$)jV&bJs;#v{nU&A&4{T0_eHbq_-27@p7y-A;A$D_wwNx?vC6{d^x_oYZ_oUTcN6> zFGrs~j2@>@^pAWcKDAR4Ml4u4ps8Arue0SFRVaP&6tnZ51c?6|p^{{L^v3g*Gxpno z_t|4sa_j4h{=9SGR1*#YGd11opa9j6vl5ql)UD;0wp`T$)G%7DIVS>p7ueXdtMT;I z+rEsWtsST@P-xU}RY0R6|8p@p8c|{??0h*J)Xu@gtkkA22hn`N(A9GG^2+S-ciLZ+ z*k$xTEpuO74-I<@Xo|^5<51#Lw;Bguq#X_EVgD>xmB=?xw&GGIX`<=?TzAS~-Bq$P zY~8$&`!dPZQ$fq?`Td6tKS>=G(alCw-HW_cV->b;cKomSXd0Kw1-^tF?)gni_8&%@ zeLda!_G_GG-myC>ZSK^?(RS#oU{V07QK}q3_`@E-o#00%>__IG`DNKVPScC%T1vPS zvrNg*Ci*jw%##SgR9tm-F;c0^y>T`ZDFtvFGLekI)yxmp?J=oqm!|Ok2saKsK@DA8 zd_s>v4I}fHA-t{_v0T*U zg@+W%UnYXJGq1%9>SKe2a+U;Mmqt7cc(ECQ?3`Xaz^%Y}8{-R9m|@tGnVfwCNTTaa zf5!K+!-8$OZ$=eTd>&uOx2=b&8Y8<3g+Ra-XtVrNVzSKAj?3~BLv>}~0p}U?89fex z4h7MbQ#Oe&YMl_{Cw21-J)4!OhLHq!%|^)F-;TCKpvFj8i9$D39QxhrzGKJvq~{>g zgcR?~SQ7SCwagr9Z*mBGEvow|Sdk1J8r8VrwRkBCeBC|xvCXjG9qWHIYalFDbs zG5x53)Ue)NlLMwlaA*tfUk54mKLMF*_(K7={g7wiW2dK2w~@=Y+G6r$b1j;rr8q@* z*KA;1VpSd1t<}3$IQZh^U~YlJ!M!IiPwMO*EhnFqXJI+^Be8eC1p2n`6OA<1a(FU8 zIu>zM(Ii=`MeHTjt-lmcC*721cKc#-0*@Sn66I~n2&g+PCOPD9BC}g0JH9Jpto9nk zs$=zK@?eD8pLt>1(x2%u#u=TyIt?8*6S{BkQae`g0ITCy>JHucybRH;Og;wEBn}s$-S@_=GvaKhiIX}O_SG>e?T>ftaRHz^y$Cq$G;F0 zWST0lM@x=vrIRMyZuLdw(7f4Vqig)#0EM$en-HElg508k_Ho11AE3IfW)@_QpNun5 ziL9fr&L!q3FY~t>8cRfpkBK)?B%+CV%82zAWoE8{x+}(-DJK7{f>$R8#rjq1_lhZf z@j1I)&+dl_!Z!kPmY7RL<}rE5kA6BryAgr3Fk;*ee+mV|yt+okaZKdrt2^mcB!UNK zR8ik9O;>D_P{9TYT{X#R+ifp-tSl%2fllq%1b8eHlOe>11z2)0?fsEvb$k=vTo*GL zgj4mxT{AqQL0fYWJ@cm4k52z5zay3o6lO?^#vZZ_i%%e7AN$nO95pV z!g+&%85?SJDT*~_l$*}dcRT&Jw(j)cat;-Ds%p{WHUf`S9fC6{?{R|P-;cc4YAA6; ziIbU5PHCHV^PLq^`rJvKd?{KXsMXRx0V-=-SQY6=n5E{Lzhm>_vO!1$)`(eLrx<8vMx`I>#d#( z%KQDjGmTBj3k2RCGCrKpzoE7PnfJUFh%CkHL-&-p`(W0>lD@eWP!8+!56Pt|3-l!y zcc4#Q=2MlUm1y%4(?kwan8;pRdg+jc2WXO>Y6ziUL$7|vWMvkLd_>x+7kBY{=h{^P z$**kL;{c0HTmGjqxS!E+WX-~nzN58kx#oFv>t#|bWk^S)V`>n|h)?lZ@`)r3rd64a z_Ad)s=B;1;lRm&imp$7C^PfR5c3yGp@lTf|AxJ?5%yu}3hhHLf%Qk;;tU&Rn4EP%e z>Xc%XA~SV&n3_bBAE7}wAfOiRhU$AA%wxw;tIqz9s$`X=%wmh?a8F%orC9ofz{(71Zkl&T za1P=>%Kn2KCF*^@ZVcA&njLIb3BVeIF@13)OpNPXbMU`JseD>a-8PnW;F#iZdKF}5 z8VK21>`NO}*!Vc@4X4JW3cdQpnb&US5Km|@=EuDbxfb@y*yoSnB4ayDh{M#ZEe52$ zZy(9c?0CMMN`BRcM-OltmevI=gC4lm;iea4L2?|f?&1GKjPt3|&GXF*r{>+QZGjh= zHo^Z@(Z{LQHI$3jl%8}Z*7-Bb%&!(6UxNOCm7j{%41sd9&?7ZP397yPX zT6c+vdiv;9w8#t%IAH}?Sa*4))yO$ExQ% znHOvi==B&Z-?bHgRDgY4Rvl`~3p{QSG5nxqOaEOtL@jrfcrLxk>HE*u5HKQRt4=~E z90vuPrk)&xJ~06#BbXBs7);)6r_EZYV+5K6F-5|{7;}hxyqm(S!;qJ>C9kmPVsfJ= zRgbgCOk-4!(X%z>DIvd8;_S1D^0xgAvPMu*Vz<|IZir)RF& zX(k({d1M~ltWk8fi!I%8Z_p3j8mnXVw@ut>pBL8gm?1pje;ep<&sdq}6MocAGCr~+ z%(E@#WB_@Nut@VfTJ4?A*?sHY$*F7Zd%NH#3r)0dA3G&)HTeR4ewSGI{D<9o(^rh{ zyy;}fL9IWfGcTZ*t!ni}>ixDL3=*yQuJsYveOviknOI=s`+bQjs(1_W9;2q*lcMmq zGuxPiBD|DIPtB$5_A2SD@OfjrH=VJ2wdL8>gu!b&PPn((yh@ z>|BSiK-G+3dq(#^wtG)w&%ynC+JIt(?}#y-RZ(U(ZgNv=bEZtUw9l}$HYFxz3L#eaW`vCYysV_!Sb>W*mn5FTr@<<=7D+f;N>lV!SgAGpZ4 zf4w>HXxEG|yjG(0HIeqC#P3*nOw+?XJO4G~QJpB!O1Yqxm649EiGu@|ji?s*%K8JjXXK{V4lyr$=qRoQ~6;}%dxCs(#OlVK$8 zi2bPgRQ@dI+i-w#Mq~%a~*S}>=~0dXkG zOE?rMtUivj+0@zRmLa)P9ev0gIjR$1AzAketKDxDPgqVm|LJ-tC`5nc#{8=5K(EUq zi+kmsnIkowOK#gQ;EuEF1$BYu>)KB`4wZ+pKGZDQ>V9>Y_k~$|-;28{6->u455jK` zUm@=kS}qb&+0e%jJ>T&?YoYp@k9k8-W+agMuXz#w+PFATB|;&fXuF7HiUBpuS@zEo zT-?|@8@~{7%fb+GYn^pV%J~8X+f}|fD9%3?WBn_rvuspq+Gv=x^6Ac?0eb7x&*NpO zNO#BVtltG{Npv^ZcxY|b&!ARZb%!o0dpdg|D>s!IVF>^LD?@9IeRNb5UjjO7b$po3 z@*Hfdwg|atycgo3Gef9nh(oTOnwNuqhVdCgP6u z7k>3ie5;WVNKb2`&JTPO&<+Wn9e};@;EVlHaL$xc!@{8{LH{mK4aY~9i^1Y6v~hcX zHZ0L*EMsDmm8LVPZ5lR0@+*rR$R{Pke)iQx5W902hHvfKv5*1QTYQFte}}%Vm&D{k z+7!d(i}6a|+tqih7mqA)m8b3Y8J22Yp5UU;%>U6`e?wi=fOsl#1bH{Y-Q=mBFMPAK z5+Pos-GNkD5oaxp?RytF>M@OzkLKqiEhX@YKk>UZu3Vod35KOFg|cs}Hyk8obGnDD zoxIB1gcG46fBsvD_wR#RzLj_HFl*Q4Ef^h>%J%07zTsCpFC$;vb*FBfb*$H`rUj1* z-_#}HgBL5g21oSQ4=xU7?~cuJAqTlNI(l&66R&?$ZM7WrpoaAC=rZdZH8x&9re0=* z>*c83M%ikcOQ4n;>re|)>U_IuGxC~nJ@20fD%FH+Kb48Wqvk;eUfQh_Jw4bs+@k&g zrYo&u6?HaNWLNL)&Rhth-a*+cs2Zq`;%y!0{cd?A9Kqo8?kYI#pb-jcVMc{%pL8wI z!bA$aM*cwn&NadKbzZ%{s6vP5279nyXP`2PPx;!(oK+U51^ydvx_JSZ3!BmtRRl4# ziqQtNOwcvmQ4v4aPK@H~{fU;wx=6e~yLVM}IIqoV^e4cVfP@&yw!Q>Z?<^|xpR&|} z-5`=k3OPc^9(L~F?`fC)cfea#bYCJ4)Y}$5PT76oARl3`M<{ zbK8wL-ve^qRYZ}IrTF`C`lF7TtWBb-Vvf{MlvHft{%~$yharbtQ#3OZ{yJ(Nzgs3n zh2Ej=28EF6*{ZP%OyX4UiK{KL{KZvV5?@;roK4umxn+w$T(PGWFhvTk>1hAaK*=%Pkvip$aL!XHoJ)zKq>S- z4%{a6XKdlob}4~VLE>(1IVo_mV!WF?sin{OwRexaiJO;?IVehq-S?X!W-_wt@FYBv z5cJjdmw&KugBfUBbDrI8t6d8|Rq(vslwAZACFOcjjLWO7$vW9ZncsI)mW9}PP`p9w zF@%TEob!et%2!Z3T!4xZv2?w_&1Xx{l}Tih%U1ZH7H`=akPa zrOKSu5}IRp!USL^iB+Vy9>W#ASur!YsfuK=wUW6a)-X+ysdve6a5GV7&0xSx*#ER(MvNIpK)(y36)()1pSC;Pf#xM^_T{j;k~h z?q#J4u?tC-0&vr3a5oq*wh+HhPtCs1l3;t&by$J>e&pubb@Ae6NnQ3R`@wiJ}a5iaD)#WkbL7{b&4kex> zdiDKk;wAiNKDk4Y9~C3Ph1_>>KaG_(yc_5*NyntkiXBBNs;HIyJ-RDNw%DeyE1c{; z+9vY#-Fcq1_Rp5+WhDus`?Wb9Xbyk6hShG!GaPz|uEp92$pu{H_WUK`^Uu?c$1?|b zqSiu!!2@o0!DtX1ezoLPQ(RLY?kL4g-_bAK4^z$md0}D-O_~Pm5IbcCrTVIMB_@^ zJOnk$EKuSDYpx1sqsD9i&mifJQutT$-ws~;_v+#(Wxo>5FHEW+FeN9C%64K`bnpQS zTE{C^cJ8B()x3nG;u7_1PY;y1*;&Kp8*tTNM>)7r~995e%XLbJEqOU z(@H-f6HGaIAT)eVP!+D*c(N=~)zSQJB4d^w(NQ&MSBg_YwOj)W3Mpa5ZrDpYys_D3 zpcPP4+S?z4*6?W)h`|XiwilCpCG@lFo4J1H$HQw5kf`@|VDTYOj}Vc`_<8`{#IB^` zttF!T>sN40^rlwA{F(0o68JX?WD)H{!4w_gWO_Ba4|{kpHG3EZr8_*m4u$g(#qdNz-q zp43>y(fjzBP)n;G^OHZ-^DS~=%`b0RM2F`})%D~>^2uqnCn225qUVb5h>9k{;y>QS zB@P7gZ8+!a%KV^~!|`qEo9~CwV1`9i`O7(`vHu{ZD(?FiAed4ApyUO`NU6)y8X>e? zFbsrxUh0fTzgnw>YfZvcRQ2~KyWqSPn%RNp;CAE z^KaVxs+y(LZYwe|Xa4J<*$%EW+Bne1l30 z;S}^qrwbeDtAf;VyhpfVuvF61;eU6p9LlT0wABq#6?=4{YjY?i7Ft2j4luxh)y6(O zv-^hi0I94otv~d`Q}^H|PEYdDal6g{cIOhJw;1Z+k#Y>*EqP+BiRB(Egg3_MfWa^R zCX7+nifO6gZ5Y+slQZ18ankDNcIQqX&qi38o_qAnRQ7_$>B8z-c}3|-O(U9e`&+3c zj@g{4XiHMe_Omnxi6PM(A!;Z}FIuB zix#mK8U9i4CU?LNH}li!82Y=UWN{F9$B*u8lwUWvBJc>(c8t)!j8mT|XoPdE!jOC} z-L4YeM5`KqSVg^LHanQhy!cBcI?$6pzOLTqe-$$y#wG@ZQ#!(+)c~Z5l1#?8gP3~t z!prd*kif&>u6zKL5+J}@Fg)fcCyI4ChDUB6B?G5E+4Lx&+- z8|MfQMX|xOXZgjUfSt8{-jkAeWawXVz>>%Y7BM-m~H^AL2+Wjg`Z%n^EH(dss2ghcLO=*1QDa@NBFHURTZ$7*)PE1mjgo0CrBlEDv zgjQR^b~R!(BY}&&rDa3C;OtZx2;+qjFk%4DcZ*K+_l})Y*w4ILn6s9s9uT>%R1e9T{wZWD(tclpDXFY;8 z#de=x`*gQo!-D|2i}mH~Q{3rEDSv#lisSzrb)Lr{4Qf!7Nbp^~c*YK?4%WyfCpX z$BZ+?sD{+ifWq(DTd3NDI|NmIV}wyFcI8w<(r1Q@q$ zJH!3QTR|C;tps^XIz(9|ur#3eV z<=PLoaL?L<{a2%>^u`W;OvGRouXoivvI-m_+zM7~vwOF%A{mHPF21oeh)DVOn=x~= zzMkESOZPrheF}iL>j!vq@v5Y~Q6&DVV_Mjm32JQTF(uESMb*L7rS}}+%c8e7E%BT; z(EG!?CbJacJNDbrHaNJ3vfBEXPGlc2ugMDa(7z~>N5bB>0fXdjfoZN^ZmTOWZ>1&{TguTKE?Rf)-%>)UVI~7L2fF|)6L8>7Z>)f2 zV1Pm2VshVUUnQgw@{hYR2`a=~ZtN=#)lGqz+Za9yg~SH36ZRDZVG1h}SJY{QU~jCG zQ%HBAS-7YmH&f1;4HWs14>ji|3#}4mcu>!oR_mVZMM1^k$6Vl zlyn>5TpCdbxctE>4=;GY;jx+MsO~^8&R-)JKCcR*5&eebP7GlYA4x`4pA@W^OvIpK zsrYr#fb+{>9f4};ADYj}%6d3mG_R|60bQvNNjthj;v0`pss!AjXfPt+ll>tNf(9H? z_lGdvlS?pAtnKvG>*_HHM((T8x#?JAYBZ9ou?zJB9OS#g{$*Z#gwQ+KW_Gs+Ka7*0 zC+Pb$72n5VodVY z9^?lHM2ht<^zHKKyd;?w{K3P~;Fp3O-Fpff%_}ZPmvn&*PW)b8R|Dmp#`Y!@;dPD9 zq;CvKwtFB~Q=46|E`$fy*g*LZ??zBmbu(6o1cqTV(fbR@01HA|Xwx8fQ&0%}=o6!z zffW|M#ZT3+Y&swx*pg zeu?n2Pm9e=2ln;kp!6k@w%L{+&(Ol$94f7E*s6_r zZS=fS0~mz)mdrz9O{*piTwmR+L_((_U>^bR$$c?z-IQ(UvBoSFOTB(tE1q{1CNb$J zgT($F5XsE?~|WTZ01B%&Tcc)LUm4@JM|x z6AsB4nmOGb1NUD6fMu&L#`b*o$qfFG;m*zNFcdbe-16K5ajY^N5QgW;;H6qE!Xy@x z(Lf9;hu#YWG%C5PAqp!crPwYYrQ-t46wu!|VmgGkF9-dNOZAA=A{wAB8b4Ud#OU~ZAbu`j%AaYF}So!GZfA9y0c+frFxL* zdta|O(pIv|wP7nv|Nbi1r$zL63Ws>|s9}l!ImNji$X4 zIClAIz>SZ9=$WKs{c5!4*8_|!>j*?j#Lj5qrtgGXRjxc=4dyNIF8d9hL^IvskOw;S z+-^-qAl&$!ACwq#7H)65(2c$;#psT*SW@KVqsOiN-l#`rDGH_O`|Dwcl0m-msyymqU;u>OqGC+B)Rz0GC}keCpwEKx=*T&jfq{Hh7HgrteWel=OXhr@a66($ ze;E&dD?#LAN?_q{y7qhFiDBgu8BV_n(rlQ?B&yJKVcO)hDR_w`hrwl}Sfe5XwWb-9yoY!AYeZNN=6 zOHsSMcWts43|ylBhkMrC_oIX|N+4hN1+e3P=2ANa0A0TNi)+~-ayyBZCJm8Pl(H_t zF}>y3(e3o)68KPV_HR<5f_rG4En9-dCJqtsDy^^D=^rj%!EHaVBc`QB@lbJyV4Hsp z5}}iVgk&;hDon)E?7vdYs`{b32iz2xl_CUCTwymmi=Ib0Bs#%ETT6{kHXV+5b0N3f zJP6)SbC*qZ4r0Lq9{%Tb^FRFYoOWxVPWw#l-*911ow37rXN3UOdtw8Y$a-+zrQYh)K2W?m#74Qd&ig*Zw5&mtg*Nam^B&+95)B6+*ml zfZX2^fNfP%5D0+)ZR1L>>1$73mpg1)N&=Vlx*!QK-5||K2wW=mb<+NMyuNqICh*Aj z_tnW2UI}UXSA!a7Jy=Zy6hMIg|8u2%_rJ*kr>x3LBwT@Pg|4s8P-kEMWQkISfimP& z5g1ilmo1`XP^+p)Xh*(-YpG2E-MhB7Y#gxCq=Dc{go8ZglX5y@l4HpTYFdNPa(es! zeO0Ty?~{~3&G;;3`OMOu4V+Bd8>k6A08-TKR;diB&K>dIeR#nCA0OlgKuQ2bQJ^VH zBozpd5=~JuK7J4gd_bZ^DNoFj93~`+v}l`@WP2!w4Ivkev?+z6*K{to4XG)o-foL_ zi>_abF4di@s;}DTyW#WhUD81U0P$l#OCHP&Hn6be_RuIGn)a99Y)jR`gDz(-PNAx! zQibSzB>VC0`rEtg*d`TA%`XB3JP)yMX72Bf{aT-;d$#TOdv_@)3SMAx%nVS6KiB_@ z20fPD*Zx+wsF0#alh6Yx6C!)=TYAs0_n>d6hk=#XJtcQZIRScu8G68H1wDl+LM{8c zGD5fmpPHwH@F#t1eTahyaK706bzHm)>E zkD=+oKrvEG#pZsNA}ea+Iatm=#ByGr!u zihvDG%t`R7+O=7%|r^%K@0WNpl3BFWTggiWm#Wh zU>SAF(;r&CXM3CY}UPO%Q^x|k-TDQ3uV#ViG_VgV(@ z`Gr)FP~WfOl!i7zyn(mzp7Mu;2#9wsHEn1|iw!d@VwMH> z7LqZfHS9uTdX_%#^=H3+&1xKOMTeUv(6JYuLEovocf1l5>&xk);0awd4bij0bk2aj zHc81{rDh<~&BV*AAfQPEq`a7!aIi`(luJ}*FX)YX8&_AijXizEywwW9;nOS9VvsR) z&^XFCmcRN9?3O*hPxkwT5v~{(v&^1m>%MKgr4q_Il;(tc}s1vYv&#lV}rTO8gx?l#^&?hfAB zv@3GGdwykx6bFZbK(d|TTM2*xrHZ$E_#-iI7^u7>gzLv91t>bh&Ubqo|1bhn|naUU+=XL z<5jhXT7Ix_$cm^CW-ihtZe@c$oT>ErZ&;A@JAXgiPal{wbS%enBIn>d(M5V#S9|9F zGpMS0LTaO8etD?VcgE`XY1974!#BCb-LsJY&!^AnQw~1+kI&vD59F2X&g+~{+OO}p zz|4GBI42~xMCp+mhNV|~R^z9Z`zP3Nlavtbjw1LJl7A8pe-Z}Y5{g!#h3^0GM39nE zP(eUKK_em|qoQHp6A}@VkWx`gmO`6I_?#&8OgQ?TJZ5PjmRceug6cJ%KuotDiSgfJ zeTzW%0MI5VAA=4)m=Ge3AgT!c5D?l1h^|SFI83j+jy#<3y^q36KPCY__`x6k*Byf; zCLkgqrv(BEh5!o(4~&k3iG_z93N9rXIRy=YM&Uw)iWDY7lvpVeB}tYiOST;G%2caR zsa91~Rl2n6(5bfueK@Kq4#lVmED$~0EzFuK&@Xr1BxP{n2R?F{{O>AJ*Q(>{g=wyr zZ63$Q~0)l zApTd4MreAxBcuer4?J?K1_7MTK@^UAouC4dkb;pA#jZUxlBEdW zBYbV;$8K)LM^&pUYbg>J_zH=Ru306O+c}B8N}%TyKKXA_#O-Vcx0Sgnscd$3y0w5H zP|yRuVSpPHLNkO`R;o4cf3}jI*Y_u*+SY*;A`gDE6*V+wFy*wMPOJlU{*u2 zT1aU@${bW#vZN}qS`!+IFD~SU#@%40l6C>aqs+V-P;kQEQXlgJA*fq5ZbkStYuHLl z;Ohp&i;alL4${0QGKGw+h5#!_AzAk_0d|XrP(SBz)2;(Mwn? zqL^!)JXlR@c}8gKhV&HN89k>e9M%)hsSAOMqjvB;Rp9Cvd0+<|0S?dzh{C?b-c6mh z1Hlaf(+(Qcn3?PPq#KMBENw&57*(Ut3HVh-lN_3Yl$2C)pEmF{V6}zzjeLV>**Tg@ zXl=*0JN=~81mB|xN8x9Lrq!IIrRFzGq;1PyhkEAS9J-ocHS_Bu9YVHM?Z$?RXf-!O zt!E}krP1^eo&iC0R4<7(79?hZC@W{^#$|$v4xdQmChaKsO7K$^OCSUSyWZJCMHd8hfJ;q`xzgKeSNFYYY#6jyQyUGdQMX{FCI?b|GtQ=1BGKVz(KtBA zUo&yd=IE%1c9z3bk-S1z5}+rE(3dC-BnCrCf{`S{SgOH9y6c%LhJ02?<@|{~Q$$@09!#^J;QDEOQ5Kd%j_2vvn1(2u3t1yF z6Sd8NwNNd##`<#KO3|p+8`dg8C4#&Zh}Xk(YC&|r0sx-w@kCsurk(f7Mo~#!-M0Xb zeu6$oTUA^tbCh`PAj!blu{#w7if>RMNx;vLS?9v1E_d0J*%3u{tkrdylIVOx53dx^ zg^ms?3&VNns8E7CWY0p%L}jRypM9JPUYkL!CQK53R!0`(tLBTa-sgxfg4;K=y0#A1 zK*1+&=T3J>iWHSyeZ%H6g8)}CMEJ@ERvliD>}p$H@`XJUfjaK^3BjnL)0kp4NI0yc zPUR{ZqMkb9tuygp9Fw5VB1IJNh{NicBPV3Nc7P#Fi3D?K9hVcw%a1YCmO>p+fz*TA zX_^^=Ah+$Be9IJ6vJ~P%CY>U5wnLK5q`6}Rbf9UZb5F?}?%H`^!1HU_?IZG<8+7l$ zMKKiswuOh*n`T9KQ%MC+@XmfxvDOof?{GLjExHj*?V&a7%}bsTGFB4O z>Ilz0s4_spFPpYLA-U(42=mFSYNotiBfCTAQp9C#8k6$2{9Q$mRSUM%@KKiCi*8p# zx6M>gC-@$y*3VQhx8U}j^tr0(DX>gnDoJS)7*d;2DI!Fe~wSbD)?g^ z{MQW{Zm}J2WfzfsWI6a8fMW>2DFomg0&p3TTqAOeEO+EUJVGFzArP++i1&!(6OnJ^ z^5bn*J7hOI>+Y%?`nSoOcH8scbD^-!^aErupsoRR1T5T?!0HdS0_(t&3)EvmUQogc$ z!;;>Ub}3CY7MdvNNGaJb)Eej1q0|x{K`gqpy&46?>QnCz#v!W{1lXJ!O(AvtVOHz` zGzpm<{Y0WEVn$5L#yr?iL2ciY>|lPrNSm~&Hj_d4j<35Wkx>RP>V_-Ziv_x!b|+C% z2~e*t=Bk|@r#(K)PmTr?iYfw;Vx!k>Q7eozjkFqRAh$pTbrLtFsA`jQvwTgrnHExQ zKz^MGPc=t4M@~72fD-^?8OG1M3j47gTZR;=HXxth%vD=I*j#KKrZi=%V^{lgnyWb= z3FGxG&t&QVp2I*>nPFcynHKg+@p~k=(k#$rL$&K&Mc;UfHh<$IDD&w?uPr_+KRKd)(c_T%+F zqC`cJLvP82N+;GIFs7-l=q|o~@UOLnf1PBk%rdk%p zfEQM`|G7mE+Y=2k))9gBSV2>=3UH{!h!yTU<&~-Z16Ejk?w4e?M%rj%o#;?FkC?&^ zYgd!?y_w~8r6?|0L2VE@9&K+(Kto$=+UOS#KQWEWVdTE*h4-iwRfTqlktKpaL5&My z7W?cET6jz0llNme`4E$;dUt^)H0Rgr@x7;6EIUepHx3V0Zk!kH@cC4|0BrkN4VmX1 z|=Qa9r=yF3)Ol2_`H3`*I7K{=Sg~3;Ju}6wYIe;h9_5xnoHVJ4qy~U?W*bLp4FxI zKo414-rYQ5v^7~FlHZwzMoaa{O$)ZD2m0RfV(DxeVtk0SatIq;>EK|=%gzdQ@VuuL z2=|a?*L)wp8wYUuI02hODkQzf(aqV-c22M(4w!OrJ-?suQm(Xbj?;?-ZdnCMTX_LA zwN4jZV~2=ltoO?1F{Na@8$gJBZ$0auTf0^PNTD`v=cn22MFTEANp3PWWj4q%rGPp{ zFop8Br{TOO^P;6_L4m# z^nwTxrFkDb43U)I}Ph!w_3 zka;KHxi2%{K!nTcaKieA9cdQYvLzVV+jiRa2)qA9Sw8~AvC%iq4Q^8Ysn`>PSE5Ek zqKntPse|hSgI6dK4E7GH&0A!QPaogyv=TTZZ$I(C({1Fr)QWXH5jN}k)fE|#C85w` zJ`>+QoHc|CXoJI0k4Q;;N2tnznUNzZXozrL>*(+2P=aXR*lI=o9-oHZ#vN!V@U%md zAmor6Q!9m#LQw`e7d^{BN0s5Rz(Y_xp)+7N*+o;w=$oT-kYqUngh7D?rVzWJ5gZnw zyBxEXZU_df9SjUon}g-Rv`&S=Xa_@PM~WNN@q5L!yA%9-&I}8|8ju{=O?R)j7Mg+8 zi3(6ytv0Quk+BY$5|aa}&q>=o197{jcJvJ)R=4yq6_2C9f#AyVuryfdi8pn#7`1ds zQLjp!|1IlnHl0FXOC<(Nn^{Jj%#sN6slwOWmZj6CafP;YDitBrEYJ*+-To&DyXj<) z*$?f?a)1n3DT3RXZDSi@$Dw;UDjEMqT?%9JioScTOS#|IVL%-YE9gEnI-6sfBR8+d zP!)+&i!5x9Wn}8*t_bU}c-^a^xdU&xCfD1a@K+E5V%1zTTLi`2Ynwtz(FLD9im@;FkUeg(5!o8&HOCnB1*zIi!1C{mp9Zx=!%S99k z#518?ZqNJe0)lG71gE2N7#WFJ{Vj;QTK!Q8CSA50zfUp+UOOwB5)2{w_0G&ncdO)= zWhf!JM0Q6E>XR1Jr~zlh_80%beGaRj&dkm(3vM|3-`0%HZacQk?6F`V4fiC$!{EDT zDS)X)$eNGaoC!rycd)ZUKv*VI(x*rcOP^&GWZmp&SY6r7g^}d4@=((rS>e3>m|H-) z#FhNdZeC=sLN`y(0s1VmZOV&l+Gu*~;nMuJs-cOZ<~x{!1MwBQ?I^0CC-3>@s;H>>S=0y+ zV7TH~2u7I|QOc;LmeK#3-L@Zi+g7L8svi5wyi9zBvSW|8@k>-CAcW-iIxepO=J zW=1pJ<&7~lVKZiR#xJ8nlG`kz76$3z^k9F>!iZ7#s;b+?#3Uk8b3sR{KOgVMh?Wvr zDL4X}0qt~AiTQ;p{n3|sU~p^`+XybjyCnnf$@e;gmC?IY(9ys6F1_e~D$zYVC9Oav zvK*D&RHmqpM7Lj+yF+Umq*z5dH2rK}Gnu|=8d{>+10cqZyBzuDiB$xtQA)^gr#Hwf z*)16oLP1kZ~Yw2jU+EFBQ6~( zB<#4kSd`J6r!w<$n|Ezp$6EjTM*mXFVz$L?I~X?#JTjY#IRzTqbLbS9E(?QMxIyQm5&hBqBey8tUMA**vF8G}9wRkErtE9MUNY&hx z5xsLdil)~^9N9v&O5MQY+$|&qte~B+6)fvh*#6DYGXBmv)P^JL1ScW_~BEos-xu1t}2sWAY zf?gwEr?1Rq+V6d|%nBHZ>48toJr{F5&c{c4PuJ)2qh?DFiD=oNi@xM6=4@T~DZ%L~ zSkC3*9kJ%uUssuF9%Ot?GZ;?M1rtGroUjwlwa?b;Lom^Dn#7?Xz~aY)_L;M;p4=r! zL8WT0_+lpIu3AG*!n^^8YZ2!_Vzn)bVs84g&QV#XL?)E z2lkqfI4}cQk0&yrzX}(Jd#Fo-8Nm=c6@f$J+mkxA!&U7(e@#xS-2Ii_}@wy|b zbwu*3?GBeaip-_unj%H96`pkdqjspNMQQ&0=So0(z-7Qjy`fJq*zVQxjzDcl-*#e? za@FAW%2}Ht*;~0%0?JYu+$5T)@FvmIBoMpRuP{0Q6hbuFDQ|_?ePgj^CGQRz1Bu_K zfjI9oOgG58_VVr#u=A5m$#BIvP?w}0ch7$8f!IEpD3i=;qOC1Ne^|&F5Ly>YR{~#Q z2hlcxCt#W2fW}#{n}{lV!_jCrQF!agre=8;w;$0s^TUa3qM04dR}@fhpkkyx2q?*C zF#0yb{`U-lwFvZFpg74Sdo}&8E|(~*m|nHBepjlBgj;z%qKb6quez+N=(VBilW2W4 zK}JmZ4B<+QaD*Qgf#^aTx1*5WB33sm3^zLY#6>>Cay^M_*2GT78gt14^dW?eORr{ygkOa2~?=Ih0YQ zuL|CwH7}4Ft-EzutDXA9c4+(GjR-J7m_HgI!hmJlOQ~fyY43Z+A7tXD^J*@g%NMs2 z^sD@PYS+*CNFwFbItz3OURF@Ev5wUYiT%6NHK#*5_gJOTrBilJElQXzu)3B$-&z#m zhl667L9J5;JpStX%L?+vx39iPa*n*b@~RAU>4mPsdJ(9rzov^pCpl=38}O`V3qpCf z&1S`z@ek$B$f9;__SQ{WsKaYAt>eEHwFXh$lb(h%jsfuWKG4K~-RM?N7{|<-7LZuG zH?(}O1sF#9!@8XwMrotXV;J^jD4oV+IN{;lVfAe1Lj%(P=|c!#Wjvw=8U&oCQiU>b z!!-+Pd0U__iSWWg${^+4+|NX*5H?9a=q(^XCJ{yiEZOGB?N#A)puq&pKx6&EKsqKi z^6E0NR(77C_OL)4!@%o^BiuUVcmbhpmLBg30+J&CY9eC+5Kz$cS=8WrrF*hm!5^=> zZF^RZbhx^k@T<;;?@#X!%X)NniIYn%-7A3#?6HEfo2cJ_hpZiN-JwS7)gD?d zx09mZs2Fd^3RNh1QhzgR%nf$}?Oq-!cUhXLnF5^I>Zaz@Z-v>QTqHN>w{hg;+Q5Nk zz2FnHl#Qq-E9Q&iLpzv*0&+a!<7`QIgfo^KqY-DwlM_p4b*_`6h-Qs!8G`j{Eb@f9 zJWmc<^I$!gHrGOjiyPXsj@V5~C>^iHopK`1 zL~ibv(+SZn z7L=wL4l(@2!2h(US@z!=sC|X_&2O;kCRdG_ppQ^=**<&d--SVMqmBi8xB*jq*^6B8 zC>wJF`W7Mg>ZTdhmOs|+?sVoEOk6OHW=9>tW4|HE3WwD{R=6Zy zQ*x<9SG}+}y@4Sfy7B$bdx(gHsI6FFJQ@t9!XV~zw2GRrlBPih3qI!15s4p1>#0JKjmJrICshcN zo(siOP5JRdvzl91TH8>q)<}ZP$@*_DBiRRGpI?$-U*c;Yp3JYi z9&l(Fx;u2nQzB~5yop3YHi=}#QSnzrKShkWn0$4%hTrU}FFd@hvOKfIuIG+Wpb2}i zGq3~_NnKlE7|U}CJV|nY6KcxT5Sy2{v~^x^<@;?$tgXRYAfiEwb?lKvP)%yaN<_@9itLt8emNh{h-aIxeIq*b;PAIOxU~>tCauVq*$h`T@GSaeh z$d=Y=b*oX~)skrtt!%uQ%q zdN^uV;j6A4-ML&($)kyr8lr6SboK&_4|)CA1c~y7ME*=6{ZBru-|IyAn==_dhS%n4 z3woA%9P~N_=tt0S)vv?4ufO(;nLPc)*(*yDL1t;s7nT{EZEksj!QV_)#msdqPdaKT{a_*->MziO zwx}WryRt~M)IIV$YtaXd*xC8%-RXLgV!22+7F|eMxe;LT0nhW zT9}&|Pun|u`L-m(DQs4#RnCoRy+yYh!2{>72{RIL*g_JKN=y<*Y_LA6NrwyOU~kV{ z@n(4^H}Vfs1aNQWD?sSKGQ)^=yyBis`W!RdoP2{q1(@$_{wNqRQ4&QarA{ONofrbPRfl4?_ zmrtE07GHr+t{zW32$3Ul?4W;mf`{0W&!A&IgYKmiA0p*Oc7D+N6P&}I+wp3|BL#Cr zN#wonaqd+#Y0AzM7w<#pmkbS=A~kwwsPbjbAa_x$=qncf4)`-j53m|FgqoW7BT&I_`_+)PU1sUpu7;AVBAJWWEMpx* zC)ldw|8wK`GPwzm=JK26V;vpA6e^2)7nz9NkAdC=5t57P^OPb8L+%pYqSPPXGG+Pr zu$NiQiE$3>Od0c<$T-V8_hd++PaYwBIs$FR+Uo!#A#jV1aZ(P>XLEB_*d(GrQQRzm z@X0h1Vu}<8uO;QCI3!sB2Y}PS@YeZY zkG;~-jD;2z+ce++*nP>ckP+VswhVmuL!intSrCUAW>p?fH*)iE$&JY|iGvB``PYN2 zL_^gQGCoWfzmBgE>kBaQ|GD|aR1pvgo}7IGQ0j&7r5h2=z*M+|hG{;YsvjQSHUgD> zLZ(WNsqjF{w|$orVQ>UNjpNYjiX77AGuc0r$-gY%O^yk2i(pp@y8VJ#iA(__A@Ja> z+%qjMm5%!x-X<*cze42R10ij{05-JrGQL!2&9 zsUhM{5#+Au2^atF4?*!}NzFei;|*}H16NCLmraL^&|A#dt^#~ipz_*;Fd+?0E|L7L zxA}4ue!Zgf!raFYxxyfU3pW}-bmn`Q=6Kg3jhHzt9?jU#C@Ouo=IUI4SZv5$(KGHE z2pxxKV6k%i(jZn!F_fIP02jz3;HI63heh?f;ms^-0F)`u$S|DNJu^0oHsv}uZkbRS zFXF^%J6eU4Qfqjo({ECYb$1jDjE0h;$(a<^-0S(As;FGU>`J>vm-9EZpmU7IehvN? zM%EP4XG(-VydinJVqYocy(S> z0m|>}OhOS=%7h$7XMw$QXD_F6EyhVnMv>de_&Fm`^177v6dl)gR8!jew0t0&fa^Q{ z%NlQ(qqMwSfd}DWGUfK2gy{=;a}IOb{(VkYMdvo^ApBvjr-JVD!lTo*xc`@9MwT!`8sfM;)zk;}q;O!aBh0#U z0Jj3~wGubZQP{N9;?7hk`yPlH&ql<5G?PJR(@*b*P8v2a;#=R$MFvcY%IBkM4_REF z$w$P!j+*H|!<~!U*dmlxLrT0pMKK>(mCM9yd~7`jDqf8xDcF984Bp>Z7qu&U$ZX zWB{cflxuUpIvGE;InK6-Wq2}NRi@J)?`&$t!2c4bO8ApQUw6*ySi`modo>skzgzBi zn#P3cjGSkPOOO@|6y2IpQQ`vPfg7T9Y)qI$7e)MwB8iwnW4+Te7_ns?Jb3?_G`f@m zY@*e3)RQ@B{j?^|Xv=NQ%>E%m8~6ERxK1-9&Y%j&X?^v5HJl553HCl;`|x4_O*+Y> z^?#&)rRatu__c%`!$ZB4BH;Xm!wXjwgjeU(_fl_hPF?ql0;Z2{0~@oLugKU&cpck> z;os{U-g+a{m07IbZ*K4zt+CoP{6>=8kVHp%#OH>3hMUzYLA3Ti^?C6;E+Zg|QmGd( z?#~w_z2DU{2e}WsH9_BC)1w@fvNOTy&~dqJ9`82v3_2uUP{2EU3B!Wz4KhNQ?P8Yh`B6Hs&p89%4!$5t2P~TVh|_ zIbcM`3B!66^zBQX^TCuN;rwML7S{tY-MzVK&PtJibDn}h;h{+hQ6b_Tn&%w=r}^4_ zO@obE^lo(uvdf}aPdFqp3VEQsf(JHES#Ip%9py>5o`}OVZA9|a(7=2D8|BcY}&;uMKs_t4q3c1Z9@xkIRjVQ+ZD%x)RN0R(F2(chqySLNiV;XBVfIyUlTi z>Kj6Pg7?O!B674MQY>49`vF4+kOhIJt<3MI4(SCv#*+eb6w6p}#mrru*SOijTQDA! z)@x~(lY=*avcPGA@9VGP%NS(YPZ=Z`@eIFE3vz|FN`e&krmcFX<4aIH`7r4ZS(~H=7cD>q4<6F|H#OL~jm~*V zjD|k!iBB#|)BJOOCtveKpL~dq?pgjstB4|K>i~tKhA`J4<_Uwm3!% z$TU7mS(I%GVC4F}a>i_#K(YMdLZl;~d^3_6r7o$(5oWTFnyJbfEJ(KCR z7mi5&}loVC^pT&B+h3g$xT7JIys%mF|efOQX~0^HcO?o zv<*1@sXsx!80TJ_=eS4j`W|Ck8esucbhVtxA@p1DNnl2jr>nW6HVhGqK%3(RedBuJ zbKU{+Cv4r6h@jJ=v%1upB{M<}!Yin1du5tg<&etUyo;``#&|`Z9}AC@Hl!dwoSQMi zJgg@q`wQv|(=6QsrVLMWL`l!QS^2+hm{w%;Xe7*~#KZ%^e-a?bQ8e3=saX!pC*jis zN^^R?&taY3;j;+c7IJ}7zKPyEw#3^r5H8azQ<8f#I=ZTt5aM(KftBl&)@Cpq6eL$y>Vg;1!q^B1zI4zAWx)uFNJ%Y@1-l_jsLn7fAq&Q!$lo+|vyfC?ESVn++ zqZtP!!sn^yI5QP1;=o5N|9{r*>g#tp@`E#`&CdRH)wKL+9m&O6{dRH>sZb(IBkhJS zbIN-2ZA!Ju;c&=%gLY*{k{#P=Vckqb3mt@ZEjJ3vy8}?IhT`5vB*jy@<~|hI1y~{! z+6hg#w|}`RP5$4SUiN75XJIja>#+vOzItPt7BMbj8woB(fKZmvT7b_Yw2|p`l%n#2gr@Caf8X*oB~*r6R$%3<`8jMCENd zb+3iSZaDwPLH2B^N`7nGusmhfc*8d2@VBQCh_BEw;e9M~90im3!B7^6$Lr*v3#j9| zw{T=50CJFRihtCQ7y8n`Bt|D&#GbGLQ^#%4eLLG(tPa4?NoKPM-wqyPR_}xTZ!aH4 zKx~hTKk&;h2Y_)GC%8vfNm5Y+mZ{rfUEu_Ump{Gl%putG!z$QtbSC8Wg+d-bp4whK zzs2ItbiT7Q(tcZy>M8)a3h5{9i!yl8TMcqmA3#NRCH1g_c6bnliqXDnfTs@Fg@0e5 ztB^R??1+6Fn}|y!k*`xRt8*fV#Sqd$xa@A=;yPiqblNX;v}0_ zzpbu&Zh8LvSw((19y;$6v%|NQf|sEG;*=jYGEV{6Q%LIm;MOVdiB1eI(Tal+k)%yT z>ffOTzz}0;n$E#(l3Yae#;+1Du}n1M5!=4G4YU)vVUO41C5j8;i^#sXmB%w=O-#ch zw|+AYG${g!8(rMe5MzR&UqxI(x^WI;WHHg@w|BQU#2u<{IDR)-aPTmaw zpN;yixAo<|*mj~$dcmF4c_Q`QU?F|0H$F1;?AMgT=_SeBdb~~+N#hw2LcJh@0D!*NP7H~cE&sj!o5JI?p^xK<#;to>_)Yt)zm|;&x?d@KyJ%9dV{G%jX*nK=oAb8i zn|X&|N476fqAm%W{|uVlGRq~Qy8T}dNCQ?pWA%|41WTY;AWE7F1$I9FkJNM z2K7!ejC4}}0!g@Ed+F$c(wjvFhH4$g` zgP*yROLsLQ8k(RL&(o&>M}KZPQUG_s)(-i0L`F{haqyygBQFk0^~UPAZvXh&4izK9!O;9wj~W}sK8Jgzir=Bg?A`-_6!OuwdD z@b8fqFs4IVix%lVKb#^uwIdeABWE)?*!?3zaa4Ct1Ts3qKQPmhUO1)DuMpN`xcLz; zR&nL(f-+^YDchaG=9vGLVCpcquTYqOa7MaVW_lGd?l%cbBvKWhn=VMsT!xrh+)Ub2 zo(!V=r9KuO+FJ43S7C3;2Yx16f$nC9Ue(s*@c1jdnfR_gUxBY1KEu^m@Wp1t8Ns7` z7`N1##hM~3ley(G69>zQJR@STGI@**B9+Mg@6tB5KxutwOH^t+MRb|KPgl`W2#B}Q z3;;Pm#=ki7OB}0^i>*ocki2VxtR3obu|a^nzO+ia%0fzA<+5LnzG(J(q?3uub3d%()4-35`087w6Qu zr_NR5w}X2L@hI#l4kImyoBL|1S2jr1qn4^l|Q@*z6e5}@8R2^H~1h(1VFC; z^pbB)RL?)9Ksz2<0kJ&0u?zdq?L z(+ft?r;f3vYw#l-W9tjk=Z(Mj&73F(*{I)PEJHq9=E{sOG4(h(81DvWmttRIZ2+en zy_pjhDZk#~36J8X5R<%dQ;5d%Yy?3Qt6pS5_3InLs(MoMq6#QKTW$SrRbChAf7p3W z8~W>gdfzOhzJ&EvXNCA>oAa3S|CzYdCE@G|FCJy0R4;V{AS84_!Xtg8&e*KBu`$wq z-SMk^7r?+3jzmy zO2Xrs01-yao));z!>KOA@;k%0b^s(u42?FP)$L`}UFvc4(R%VbqfEj&=3uz`>!IM4 zl(L+PlI7Y#<{F83T97$!Pn8gsUFU>;VRSzpRLI)w|%w*L0IT*|ZfEF`#YQTHyZZ)ujFy*Y}W zpWm|Z4f&=l!Mu9ZX=t@w7csNWSisTi9i_PXTIZc(q_F(Up>eODEVqC@@AF-Gzn%`Q z*;UI=^2eKi)Y07;>qp)yHU<5j4kW;fYpZ1TudiO;&@4ZFeGolYH_-T5|DrGm292F{ zWHEpoUV$*J=xy73*LjBFal0J%7OQfYl0Q1UZv%shg$8HV#1kw*#4AEqCgLh-#jbRz z>ZbZSPKCos$Nj{)-x{Qct`D%RpDbhFqi&Cce<$_By8`lgQh}~yL6t7GkbA0YU3yFM z$V6e5H)%dD!Ux;7WOaBahU;o%`Vd;L)ps^Me?5Q9V%+~J->>RwKo7Xb25lyV%c+d2m`o`tDA;2)YN zmtmw&M0veJUsgtt)*L&OA)*%A1W>hc{>uX`6O-L93mN%IB5V;=*1T(eETfv7H8o+7&bQyadjeP!@l~_@IA0##!3~3oVuq^4RzV6k; zdI&2W@@xF1aYO3}JpT4T6M~w6Z=cIaq610A=`^%^` zG$m;y=y1mQ5JedmGAQ5|50KtK#*joDH>b+rRlo{E<4XkaLqrf)rzI-iW{^aLfF~}C zDx5qy8R7+*b)eQ^=ZI)S)7o(=Y_NJ2u)=BAFE9^pr?})?{4}Ha%}oB|NN85BFu z^Syxs59W2JzZ@m8M?8+dxRs|Lv}qWZtT!^eA0omAD|2w>J}w!tDS3*%W~chiY{{jp z;)}i`!kf*jz7zS=HwVivF=}mQxL56yfR1!Euh;bv&T zm_^27)Q3rtvNV|hLI`m&AzbmsBcB!tEwEaLl%PXdPa_55tnMztpxr=3C`Nifm>1P6 z=oiEPz9f6VW%0H-747a2SgB|I5C0O5jjZ_W?UZ@sURz}+q?!1n}rQk zbDiO!mqQ26XNcP-VvRI6xgmD4R)?p{{`W@1gGt?9J_Hi9zd@Tb*{vhHCp+eiv3wJj z7c_pic{G9t)4C&N#I{}3lGIfz5Jv27y%rHWvoL3zCI)t;Z6OK8M@Qp38$b-amBf$sD70jM2A}~0-0=o8@FMFx_hY^rlA7^#9trv>T+#i?2icfbLFiGbvu|8 zuD?}d8RtO=gkVRqK?45_6yHqFi;d(KH7`?ejQJRI8r|b8nb)8ClG%}F!wQ89G0|Gp zpQV;aZ3AyInAZkK2;4jl*c5P-|6UjYQLs%ZSh$u(Qda;;h@pm~#M=e%W3)mNpCmB^ z4b)Iy8zM)Ad~a6=QG78YbSN3Eu{A7^W8H()8-etiChOF$x7v1!VC!z=n*wN$$`n+Xsj zY;wAqLaE?)kaN?@byOhqUrB}--(^^6MkIT!bK>z(aqsm%RT)%AF3cuIy%R2>vY^EV zj}l&{#9Ew%EbGFzy4!NC%#uMXlaJHsHt263ly`wVJM8<;02P+p++z3M7BXPJJTjyA zF9ExKe4qCzTb2B>gD@6yaZDFPQVLXg97ARuCJq3k&NU3Soz z`ZviN)RaxO_&&UGaUV(k;vz9s5f{2uj(!r4I|`0z7*TOb(P(^cde zfCEa3*MF9dauVxVp}iU;ohWerL_4JW!tdp*f~F^MT(gUxEbRJ7ht3o--xR)db}-1MNW;M%g0#@@CNh zX5TjM|3ipE0aIc+?peC4;xO*lMTL!=P=}Qu_?mbF|BuSVT!En1d{KZo`s- zjoWPR6+*r5n6@VZ*%K}BSS9>CJ2(e`1KU8%5Z(K67`{u!p1dTY3Ks}gER(j)-IW^VDW5mK%}W)LBbpRd+q_0Z}~QSa<#MnGbX5 zlOI|&m3$G1%`>9^(e)Vu-$iP&7A2=a=r5K~CN9!JYm-p=?Tb3||8uCe*MBaF=+{pr zXje}dtnY&r^Ga$BetIB4e~T~D1t0LqSE>|7*bVps2dodztY{L)k|{Z}d0G#n6+jdkA7xOu@M43p@q^ zw%CUu?zdIIlC4sksFwUQSsJiSJP<-Wu>b-Bx+EOo8v%&x4idS}2B11>$aVxVRkm65 zWvf(3k)hv$s0ngHM2l*PiCe^Sm&|&dFXI(b*k4`@qN^qz#8jGQ&%_{r@^%;H)KaBU zg~-W_skyu|5Z5|v9TAfyl*y%#Av&qR%E-~h3)VhzQ405z4Aao~sENHJuot@?NTZ1- zAVh6@P39e0bx+ho9tYzU(%4_iO&o8Xfk5D3RIg!e*)u#$*ABcW^(2d%YEc#H#}-d> zivxgx)&kdph`kTcO0;4~YdMrt3tCTuUpTwX7KMAtptcw4``Y*0AN8qg{afMY;ZDPY z<$bsWgOYfcGN|5@%r_dU5lj5{h@w2aRtt=SNmB^$khf2wz?@My11 zbBhCkq1Fc1hKPNR(3R+lAzfF7a%utpbojMpxBH@SPZ>0U#Rid?m3v>z_0Z4m#yf|Q z;GR|8+xPR{>ikQkdoIhtc!kW^UtS^fe&vw6>`G3v-ZBz{17tUJ9o1?>vN;I3rIw@$ zkM`O$w>S_OYHhIf#g75N%rkvBTa$Z zXL5%dgm^gs-)1Tw%ZKxE``F&k?XJDET2;l?xJq=}s@QS2NatTE9e7WRqGNi6%#1%S z4^fngT~z%rz`=P&p9oo7s#@B5&B_*o<`xGYkFoZ-_6Je1ox&U%;{0G8m$*d_F!PpmRT&!8-;&pdMNFAaw<|ip!#8B4)6kqp5N7=;yDIZ6 z*~ZaAnLOT+>0#mKbJ226i5Ug~q&S#|@xQ19ShWUQLnQ8IUKnB@L93uLG@x(6Q+E~v z*zc}qvP377)Xm(c;8)=Uk)mlT613!)UpNlZexr&0zd3eUuHF!23#~-LH zz=kx|pi7*zXXWsDXHm}%;=WvfY43h*evA?sC8tG)C|!)Bo()6etyOW>PN#+m#gFo_ zW_w=E_h`5$r{s7b^I^ufWaEg(;n+7k`Xt@Vj=9g>*2AZ7YE5PgS;SFudfFv$r%g*7 z*t&$!z3CMiwGA4)J9m8C3i(`t_j<-xLSTr_K^)^EI5?ylmdj*s+T9dk`&7Duw|G%u z+@Y1(s_x`jNLG2-(lw#6EDetGvr@dV;8UH{(OKfc>4a$COGT}+O|jnueG;kmKTkhu zCRA9^^0{kjM9#gJ@`D6QdD>_zA&M*y=)XjQ*yuoZ87EMgNanGS#U>$#U6g_<<58ZU zqj8uIF7k9MIG0PE8voPsJ)8y&v`wcHqdLY}0NOANj3#x8RyGOwZblDyn`&vU5d4$y z@djfaJY3OB`RCOt;9t!=H*y57^L&6D%TC0v!Y}PT~&^$Zbd7fL&cfAN3IAt_;m!&~{ zmmH4zQV~L{ANYEtw^qxO5z>LsX`L#iSUXR+EaL3`&xCQHb0?_QU%w zBj$e8q{PK_wNR6+PVL5GC=RL!fm8l=lql-uKc^wMz?72A&fp_1gpRxwFhXCJshm(Xp|b*rA7 zBlB6ZrxvlMSYG)0?d#{)ao@Stg4#%{tGZb0YP20rfv0#cl9bd{MUACm;k_O~FWFjE zlP=5-&PvCG&pl&l76+hE-sFpSTH6WXlnE|5V}wOUzVGhy-hjUows(-r$fp8e_FZ#h zo;LxLq9x!UNlr1A*#|^pF$C78i=41#<={hgbau8M_XNO|i@IH3MzuHWNDcMoz0?wQ zYIWP(P)fMryL0G8EWXN`(I2ObXV=fK<=2gOV&uuzV4shrl@!@&WDO|gsUZkS& zEy~re(aS2Kj$lO)_St1t$jEtYRaJ=mm;Elv1cNoAb!^7p?dodE&V#H)71$|0&aOaV zmzdrm&3b{84Z;`|bd_#}bQsT*BChz&-Gi*9w1R_=-QL(tyH}!g2ooNkQ^_>4-ynFY zC)MI(Nu`$#;J9z7rHq&SF3JGm8nDGah>u2HMY*C{9$`GwHpIq@eQ=X5f;N90B1qM! z9Brn!b+qYuVHbVJ1E5{RnjR7=yh}`3r|pH|MC5!+&~&BB^&AYok%M{KStNb*+G1Ki zT*kzX-%Q5-D&foaSstIa;Ld zhkN*ucrwUUzEQ+|QeB<>MT)r?Td=HKkl$k$GP9^YXZ00M#*2o=Z5tLo&ru z!JU#2d2_b<)a~Bk#6+3fv5M;{x@TEaSL%}`Im-=@ablgo#@a~@YnQ$CMm zQs&AFoJA#Lb*+G6_!eB9E9*bbf!t`pDhaX*eVtxLlAuQt>T!y$34y}KS9_++Vk*R% zbI--NX`I<3i4b;HMD1n9Z`+FGb5-gojU=^nt}yJ9kW^&pTFZHFe4(RwdUfvm<1hWy ze-s`vlwHMy-ShlzZ86UuN$+k)jg0CzmZx&k2V?x3S`|&TQ9a|&uj^lj*VpSy|B`%r z4%f?Z-&$3xWwYyn#C99b9~^uVg2pWgn*m|nA|zsMt86z2IxEu`a>Q-z5ij0M4BY52 z#SWA8`puiXZMhd+IS}A%#&H^ zK#?&(k|Pw(@re^Is<8?~le&O*dv0`|pA ze0PTr>LRRiTL#NK#nwuUv>`LQ(NGwJwfLYyVAx7*6(@O&GQ>RBgu;UV*oR4*=LAX7 zo^zXu8pp9Q6j-pf|%|YVf98v2=Z2V(?Gy( z7Jfp8Tvm+cUIgp3?WAcU;e6q)i{fY2m7v#S(rChd=lzaW;3ud3+!uy61o0t%wrv9z{GEPCr|JSLXV)kZkE9+^?MrY8C3_(5)A3Y2z+uz*3+!)cntVsBt9D#v-=>}*ZFWGei6ozGX1N$s0 z3g)fKRuxHkbuSE&9T#5cDxmwCQgGl!!W+(zB9;T|`abMdo}r58i9ry-M5g$3s3b}I z^#r9uYUM=7TFShyb=d?(yS+M9Qw{x5V(6~2RG^6sMC#QHco~nvSXe=sNrW}zfXp*JTC0b2M??kUd&U)$^Z5#mkt9CL0zZ$v=n?!Cdud7@X zMc1rM7?7+5H4ORiDt@(g!%F>{j%D6QmaG9hVYuHerFb=o2F|TT zlO7~xH69QsAUCWJD8XN10DCdOtS|E7R%gMX_rz^Ur9|uw#w|)Chg+N__3gO#v(Rvx z%Ev|_@G$HaH4Cz!bEk!&jVOO5i+LgOn0?xvM5^u@CXx;@Y&l5^)qrlzcROq{0LVjJ)Y*A4{0cPE4IE^m749-KZZOF9oWQpzS?-#(!zn8z? zzv3C5UM!~L+A((}3r9gS^lh;3LxZnKW6vKj-i)InU*dcqp|$=i8Szo#u^2V6(3o4} z^-kuClEjp}g@9Y)wQO45iqJ%Di({XZ#|d2`pG4DK(Fv_KT1HuQpw{^ZJBKXyGd({Y zt(;%`>S_g8eP4b1@b30{F>`HGm&M^u)>yF`Iv4b!FBlFY($Q7!1>O{)NI@@6K{$Ot zqAUZl)7a}L>+adU6Paoso2?w(AD&8>GUGQ~x(3SayyB8jBlQ8`(kFdZ|J_7L7ta|d z)y$FceYxRjwX%AcR7PtPkupW(d@kxH8mdnfERzkc@0plEq}A!D1xK1l8}q2<)<=u1 zMiLr z1FikV#JA(a7s%17GtcvJy_}EE)|KkFYSoaWRX%&5`Ub~~%%#upv;Y~6RJ`jB%_6|a zit9#X0IjkvZ_)^L@fM;Ov0ZjUaoMmB$=w5uHJTN^5(xUdO{KVkHX2y6zT6l(qjIoi z6rXV#K{b)Uq>9$;K*FHyJ);q2vdPuJ>uV;a)i8L}>cZx3z+fYp$N^SFYhbEC_!=7b ziycWTYBBe}O`y(M#s@n4gMn|yik4D-rCP|GX%}BV+>iVIW|zcDb!mP1Xr8uqfZO*J zzAg%XH5mfI0iD9P<0V>wdl-`BdCUPs>1?L5SpdWaEaiJvRMNT~Kom zTAIsoWV%UG;9T4A4KZrG0RMl-PL^DC?mVig~umoeSS80S>!A>M4QoWqF6QPD(CpVwQU*KHdQGP%Nrs2@fQDGnQ-fq zJWXB~@6XP_&d$6<$$hS`rB5evI(%(cJUxwh`uz0i@&5X9_;GiJy2|(L%RcW{Zz%~a zP)YgXB=U?eL;F?6HdWp7ks(Glw5;eqrIg3gca_I@V+@KT&OWGg0y8v&nr1%>mxA;R zz$U!jyh5lI(I)LmW;4L-c6Ngw@q_0&wq?}XRds)Ga^?BriiD4ZzXj_}>G83Qr2V^D zF^QUt5MDj1TwC;W-GJ$ssT`|Nm;1+rOd1EG2!R<3%z>FP9Bc-frgO{7biYz;uA@U+ z&vN;-S>7-27BkN=G+BHNrvq7F9+6gC7jS^*>EwOHI4_lY7okMNogZiu5e_2}qN;}3 z%M!nG_x-rK-RwGorf~bxUAyb)K&D7)SlzAF&`sZSB;=mt5L*9!Pe~{p$y~+i#7rI{ z=7k(|?k^Cn2U2aKNPNfen%2D^# z=$l+j{?}WHa?TB7yQVZ!FZjY^COV%}j%1$UY~-vG9=o>yaTR&<(W!MmJ?gN!4+>;k z@?XXSeePAoDVRb#|?B&U% zFPPA66jkJ7KGw{-Za-3Ca}m^9`@ZPBcF?zwr}eb!R5nt+hCyxcge= zS{-Cp>4ofG*{GEb@tRut2GkF;Ijh5NKqS>RZ3U5C0aQuISxPPJBKGgEJ>9o$DmBgo z_ROA|x-_K2hIsz^e2@%j9M$yVPClz93udEKuwUg<-{m^<%1~>M`FuvktA3MRXr6?c zzM$18h7qIz@*?$81DV0JCEYY-glED&zcJ1=#p_flk2sU?khG7*EejHvpdpKxfo`b0 zT$*MJJcqe3=OY*QaJLq|B@suHhtGf6x3DWMA)0zb z8vP~2kwlfKn|)1^nIe?!RX5x}FgCzOaFuI`g&4+jW+lOZq}c(cC;iZA5IF3!a+FTX zI#%TM$wa_daB@Al(#G0oXsML%-7YW0PLw(1OA6+?ZWJ;v^ac*-Ffeceb}f{+=~xN3 z9qGedrlCAV_|;`^kH4PspI*bgci0qp;=EitdOB962GO0T90}(BK4F2jpkwj?4lx=y zltbJzsY(VIh0sZ4Y|_8V@wi;`A|!rJ6V`OBBG6cmFf>UR?h-y>gC>>}riTgPge z8b@K0OxVBgF5{@j^f!9G&7ym{>;Gr`{iyr5UH52>s?tP?H)*;|=#t9uo_XArzWg1d zf_}vWFLX}H^G=>9^IHRl%-O#=r{?5;w-S*|=tZs@-a_d7WNs;-> zgFA1%27V*4;eIm8a~j~#j7%tyWo-eNF0Jy0jtI|&)7sRs*d)3?CqSSfBO~p0YTIti zfKtN22tIuMhSCzbgSdV=))_pWJb-IFUd$$A&rzw+l@89xMo~{RU7$rS-7+XgynQIy zrT<1^^U{POp@nQaT3>G7;El3*(U00=j!_Vw-Ul=d4$B-_cOY~YdQB-ZIb`+e!ef)0 zDwHM+8X<9Fy1Nco)pRVop>R#Bo8{bdEQ3m&hYhI|Kjeo-1jvx! z*^mM$4N^c#wiykjrW&IYaHJ6foSGFPRB=kq3ZLeOr0y5|WgWFT9|w$F%aFy_Wpz1g zze-jd60?+jiv08ULf8j1Y~Tj*-G#a?G+&!{?JP{s!LDY#@FoVrcH7wft_Oq+cGjDu z0gJ}gb09<>V<6^biId$G8#i_e6LlpPB=^%qwThg(38jtHx;|QQthiE`3Y+-<4xCKB8;F<^-5n0Z7Oc+gfI?)lmS?+fTI#$P2`us$UN6K($G1DNjD-(2fdIfEvWpq~XHhjI=fVM@Guug}` zY_>9^%X+|`hleY9`0?=l(+51kFrSV`u3a;7nJn{M-K%iVCB5+9`*YMsGT|MmX8L4< zy5C0O>Y=hGdF2L`)H?xWmU>d<53_2_MkVk36DG9$866pv2pB(=v7p#CF3etC0j@q? zeRzJnTuw#|)YJ*@RgVPirLv-v&^=unWwHV)&gP?XWk)p{z2I$7HWK)qy--*Il z8R%}&bJ{rA=RzyaUUC8hMVz208$AP|ao1!)!{)pd0UnW`4wJheX;~m*f1DEkmj$k$ z(@aDMxK;TLqSYoKSgR#anF96PFdbkRvU?!s=+#VoV8g!=6$(Rc-znh zYS_4haFEt=;m)I-CM2J!yo@&eR=;17u)QggyRhO zx1gNuEqJrA=zOfcE#~Q>l+e3U<)SY~8~rgrH%2sK8TBGBtoZv`?bJdeuKG7Z)MeYN zRukWAj+A+#*HJ#yd1k03DnKbx%$&C(U_sPUosH0tQduD4mMGyo^NM7B&JO!C1upr9 z#+xY*q%nExM$;f;rlqtk67H@;Mb}*qLd%5p68?K{NF~Vu*vnf3$T+IK0kO^%d zX8H#$8F*qnPb#^8&{3$@GdiaUP;x5BP@SCGnGrB&iu+S|E)&R8dEz;^ zj&tjFIUo1BDbr9AyxBCZq!_|G(p*@ge)+`2rEgfmlYIsO73o!<1k<=+%wmXUTJEer z1mk9+Zk$WTY~vufO`GG#w;{(c{dIJB9R#6g46T0mc6kkRx+)?$$&l=#_H2=Gt6s6e z0a2sA{Z=o2^D{v>;UsD zoyX7TWoe4gzhD1BEz!cQ6PHA@`8TaH!8sz>K8jNkyb0~D__TK7bNr;2Ws|?Xr$|v~ zldt$*pgR#U580WFNHlh4AdX=k%ru1Gj@bay*BFPY(mmX7uTdFKTsSp^?Q*rC_a>Kk zq1RyCmV~Tx0R#*hT9k_MR$onsE;S_kA<$spE|nP9&{>3{E6cwp7c0}m4_bn9R|eqz zI*A8*#@qQ}ktQh0|1nEa*=iA=5$n|hN`cAO68`c=Y#Ni@#a}V9hR4*nNP5^!hy-{q z)3NyxTGkZ7J)KU1|t6$J5(V@wZL@JsJvOu_P|vtFZ7O7k(#yi zoh&&7``?xLYXdXSdZ ziRND6o_^hGz)pG;MsOj32aq=$tNj>wdsauX4Gq_DVs%@EImG_bw{;>A0o zv$6~bjD{=Kt`z5I1w_}L9*7(t)anjLz?qyOi|#vBi)51K#Dl%^+z06y^7>^OkdV-* zZb*-%Pn|;4;<@31vu+wm3V}q&=jnZF?77zT6#CcMU=B+-~ISzh95rTFUxETaFqzmh#1b zrF%k-2_Oe`A$y~}Rl-4;Ej^;=Icl7tK^yYtmvW7~>*IGd!l=t<%*%OnFo_!H#zJK? z0q1}|3Z(jHMJ?#mH_z;y=MHz4v;T6MBn;WfYOXQ(`zy}sm?sm)cVY)3*-oKiY@Gv+ zIlIEX5Ft}A3i6Xee+YQ%=>E)c zKgf9Rdh5v{D=`8LK74bO+3!CychSG{|BwfHg_ucfCwC32h{v#U+8KF+4f0z#lx__T}|}`MvvM<+ND{JesKUv+6r(Fn%dRX80R`jdtSo0>G`$ zb{)tkdkcx%J&KP&g@pG??8JB!35Z;71g}Qs`EI{dhBQI|6H{jPDbWP?)*|e--3^fz zV=l;t7v9O^?#7N%kVVRKGd%9Qn<5KyHSd@j!6!TG`&f)M>n6D4oR@*dHmbR_p@dXk zF&5?3Q!E3k`)R#kv260So7e{+wOFWwkh=?AN{XVrwb#NHW^bl&@^@D@GAfDFLX-Da z#AT5rpAjKF1vkdoP$XO5RqcgF3VAPvm!wCy8` z9?+YE&$%88kJ5*(;mc((l?{54r1FXK20!2fnS%S02QT@$OUzU|nUFmjZY#9cPU`}% zXg5G|jE_dCF8e;)h$f!HcCY4biDTHFNo4QIi4fjEYR&S)`2U73(FRkMhKSL;%Loc{ z=gnAE1T$k~tE zUswKQB;72{8>VMF2CF>8$c{R8Qg&rB7~eBik^Tff>QU~+WBprvqZDyg|7O^s3`}of z)~U#UnHGdBe@h0if2ScHGeOuaOpWV+{MPgG^VE1i>?v37u^k)ae1d&n5K;2HEIm0iXlQb6lIDR&^W(6PwKBOg2qpu{m`4sIq}E1e5(ejwM0D{*K58A9_n^@m|@brT<}~PfQ-omd)-tUJBsPr>vf3 z(!pIt_;-?C>gHmS4W%0}9EK+nVDee(E)iWS zG9XGe^9+i&Z;W&YO+Uj%-bn2L_4|Y*`Wu(Ui4yxZT3+#*Q(wa>uPGA=W#R5M*P4MZb~mzd3l{DP7K z>Kq-L!cM-GzbKuWx;Ej+@Er9?rx6IB(J0i9pRn%e{tweU*09v_$I)w?EcQvXGF^YL zHw7Ef5f?m*^m*@DkB8+3z*vHh?1ey zG;<0mJw1G)E_P+w%wkkgQLO^$xBmlcO)$Y0P904SSR(Q+rk~)|#$3q*DHnq5Pmy?8 zJOpfRj@69LIPWc36QHetq_VyJ+jN(h{n2#+-6{*O+7H(SuP@AT7uAm-ftfcWzzi{B zsGhGId-8}W=XhGAv-Ly6ul1M83t11;d8W}0Q8P*z@6Yx>_xw@$y9YQx=Bz4ThFq<=o806SZU=y8@5m7tN_^ zRdvNGz3T1yIGhFpS~c~;C(FxK5>w+Es$x}OXCPm&JMHWQE@L{uDLo#{1#1SjmEF3O z1bH@f^Z%RGP3(rT!GtP49e*$=?QN5_J>rbiq5>g~fI7|qW>^7;$Q<(|K~P+Q{Y|H0 zfrDw?3DdE5TbN9-P}%x0+PcVovg0yCP~Sr-I&20A zUBD9&j(b?#dY3YfODy<`w%PL2>i>H-OxtiFqo+4FlZmPVZeDJl|HZ10yuT1Ub700^ zPt1%nhM-(D2Z*XyxKf+h^x<13(9d6(NzSR7mS}rw_9VtAg#k12a56E?Zuft^7dOY| zNY}bbSCIs=L&+jPd>bey=kqA!EQA6z;=cbNdRP`p`Av$VUI^ixVe7ROO!pku`2I7O z1^^IyPB#Q}2mDT$9bLXGzjV?=wBX!ooy1<>{N|RhdVQL#sSW{M`DYSW`@O#?H;>Q~?8~mH`Qf%lu|*+<%BqSoxucJ0IZFsQuUy zMpB@-!{2q}gIRSf`{NI!CU-Z4^SGjbJ2iM8TffPnqc*!QlHcm_l=@({tj}}Vdy}yM z^*PwX?*@4@hihqMrt(wVTAxjW3IB#I=eqA^4IO&;?IHGd3-X}HZnUnaO$X-@eqKwS zH%)0tU~R}123y{fH_W35FRHGIX-CG)RZYkoH^?533UG=$*{M*+3zEMp`YD{xhIAm7CE(i4(X6l2-fvpEn z^(B*p0`JFm>4<6+E_+y{h+~SHb87*%+;GIS9%_;%O%MT! zPq}gBph)#QJAwYZBbPl2+o{n-LGJ|JY2CdqBv%pUi)BLt%5Q^m0kE88G%h4BQsg>j z*0ak7))fwXY6wzAkoyqX$2IJOe5l`O;@Y3*PVzEl(>ITL8>fMakAi!{lGws=U|xq5j1l5Y1)*K=M4o|Mk>DAg$ba1?tEGkhn^F{fIm z2-gii{$DSY%q~%iQ2uiEr0>l$A>Ph{Aat!TFVDXJj4>4>mD{3RBWc;Y?VPyW22QFc zS99hSg*Ku$qqaCV-(?nq6cE(4L37CkCH5$_*DyMUGE6V9l)LD%E7&-=c$urNx$cG} ze1e>iNCmO)+*Ikd#rD}xVuF;6oPyFFcU8IfTbDlCD;g%%YE4n2UY$|q_DZ*U$)-`E zzM9xMIJw*(wr|s(nwtHZr2l<6pEMo(I(6&OWusmPqpZ$(HY^!ay zJCa&M>?KHpp{8|;+M@M5!g6CS)$g2*Zpv%3#G_Fc|Be2Nnu<%g?_5GOV>) zXFUG5n|{6+x0pwlb`?j}?{n3uFsj|f&0v=_u@?l;SNv=gj z88KXP#WgpIkMMYRJn+bqXUbXB+9&K$;D7`_%)=;x0HvIQ5C_xhLv?T~Q3{bHZ%X3M zR}bczQ=Dad4kQ#PT`j2+NE65uMhRrtLRu753P^`TyNJ$$Nfc6as8FFs-O#uMgE2_J zyMxK1n1yc!*ctXej8;Ge&@p;ko+ziYRItarV?+%Vh4P9gTP>j!5J<_E`qv*S + !fontFace.display || !allowedFontFaceDisplays.includes(fontFace.display) + ); + + return artifacts.requestNetworkRecords(devtoolsLogs).then((networkRecords) => { + const results = networkRecords.filter(record => { + const isFont = record._resourceType === WebInspector.resourceTypes.Font; + + return isFont; + }) + .filter(fontRecord => { + // find the fontRecord of a font + return !!fontsWithoutProperDisplay.find(fontFace => { + return fontFace.src.find(src => fontRecord.url === src); + }); + }) + // calculate wasted time + .map(record => { + // In reality the end time should be calculated with paint time included + // all browsers wait 3000ms to block text so we make sure 3000 is our max wasted time + const wastedTime = Math.min((record._endTime - record._startTime) * 1000, 3000); + + return { + url: record.url, + wastedTime: Util.formatMilliseconds(wastedTime, 1), + }; + }); + + const headings = [ + {key: 'url', itemType: 'url', text: 'Font URL'}, + {key: 'wastedTime', itemType: 'text', text: 'Font download time'}, + ]; + const details = Audit.makeTableDetails(headings, results); + + return { + score: results.length === 0, + rawValue: results.length === 0, + details, + }; + }); + } +} + +module.exports = FontDisplay; diff --git a/lighthouse-core/config/default.js b/lighthouse-core/config/default.js index 52714e877117..441a153683f9 100644 --- a/lighthouse-core/config/default.js +++ b/lighthouse-core/config/default.js @@ -45,6 +45,7 @@ module.exports = { 'seo/hreflang', 'seo/embedded-content', 'seo/canonical', + 'fonts', ], }, { @@ -98,6 +99,7 @@ module.exports = { 'deprecations', 'mainthread-work-breakdown', 'bootup-time', + 'font-display', 'manual/pwa-cross-browser', 'manual/pwa-page-transitions', 'manual/pwa-each-page-has-url', @@ -285,6 +287,7 @@ module.exports = { {id: 'bootup-time', weight: 0, group: 'perf-info'}, {id: 'screenshot-thumbnails', weight: 0}, {id: 'mainthread-work-breakdown', weight: 0, group: 'perf-info'}, + {id: 'font-display', weight: 0, group: 'perf-info'}, ], }, 'pwa': { diff --git a/lighthouse-core/gather/gatherers/fonts.js b/lighthouse-core/gather/gatherers/fonts.js new file mode 100644 index 000000000000..0768bafb132e --- /dev/null +++ b/lighthouse-core/gather/gatherers/fonts.js @@ -0,0 +1,157 @@ +/** + * @license Copyright 2017 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const Gatherer = require('./gatherer'); +const fontFaceDescriptors = [ + 'display', + 'family', + 'featureSettings', + 'stretch', + 'style', + 'unicodeRange', + 'variant', + 'weight', +]; + +/* eslint-env browser*/ +/** + * Collect applied webfont data from `document.fonts` + * @param {string[]} + * @return {{}} + */ +/* istanbul ignore next */ +function getAllLoadedFonts(descriptors) { + const getFont = fontFace => { + const fontRule = {}; + descriptors.forEach(descriptor => { + fontRule[descriptor] = fontFace[descriptor]; + }); + + return fontRule; + }; + + return document.fonts.ready.then(() => { + return Array.from(document.fonts).filter(fontFace => fontFace.status === 'loaded') + .map(getFont); + }); +} + +/** + * Collect authored webfont data from the `CSSFontFaceRule`s present in document.styleSheets + * @return {{}} + */ +/* istanbul ignore next */ +function getFontFaceFromStylesheets() { + /** + * Get full data about each CSSFontFaceRule within a styleSheet object + * @param {StyleSheet} stylesheet + * @return {{}} + */ + function getSheetsFontFaces(stylesheet) { + const fontUrlRegex = 'url\\((?:")([^"]+)(?:"|\')\\)'; + const fontFaceRules = []; + if (stylesheet.cssRules) { + for (const rule of stylesheet.cssRules) { + if (rule instanceof CSSFontFaceRule) { + const fontsObject = { + display: rule.style.fontDisplay || 'auto', + family: rule.style.fontFamily.replace(/"|'/g, ''), + stretch: rule.style.fontStretch || 'normal', + style: rule.style.fontStyle || 'normal', + weight: rule.style.fontWeight || 'normal', + variant: rule.style.fontVariant || 'normal', + unicodeRange: rule.style.unicodeRange || 'U+0-10FFFF', + featureSettings: rule.style.featureSettings || 'normal', + src: [], + }; + + if (rule.style.src) { + const matches = rule.style.src.match(new RegExp(fontUrlRegex, 'g')); + if (matches) { + fontsObject.src = matches.map(match => { + const res = new RegExp(fontUrlRegex).exec(match); + return new URL(res[1], location.href).href; + }); + } + } + + fontFaceRules.push(fontsObject); + } + } + } + + return fontFaceRules; + } + + /** + * Provided a element, it attempts to reload the asset with CORS headers. + * Without CORS headers, a cross-origin stylesheet will have node.styleSheet.cssRules === null. + * @param {Element} oldNode + * @return {} + */ + function loadStylesheetWithCORS(oldNode) { + const newNode = oldNode.cloneNode(true); + + return new Promise(resolve => { + newNode.addEventListener('load', function onload() { + newNode.removeEventListener('load', onload); + resolve(getFontFaceFromStylesheets()); + }); + newNode.crossOrigin = 'anonymous'; + oldNode.parentNode.insertBefore(newNode, oldNode); + oldNode.remove(); + }); + } + + const promises = []; + // Get all loaded stylesheets + for (const stylesheet of document.styleSheets) { + try { + // Cross-origin stylesheets don't expose cssRules by default. We reload them w/ CORS headers. + if (stylesheet.cssRules === null && stylesheet.href && stylesheet.ownerNode && + !stylesheet.ownerNode.crossOrigin) { + promises.push(loadStylesheetWithCORS(stylesheet.ownerNode)); + } else { + promises.push(Promise.resolve(getSheetsFontFaces(stylesheet))); + } + } catch (err) { + promises.push(loadStylesheetWithCORS(stylesheet.ownerNode)); + } + } + // Flatten results + return Promise.all(promises).then(fontFaces => [].concat(...fontFaces)); +} +/* eslint-env node */ + +class Fonts extends Gatherer { + _findSameFontFamily(fontFace, fontFacesList) { + return fontFacesList.find(fontItem => { + return !fontFaceDescriptors.find(descriptor => { + return fontFace[descriptor] !== fontItem[descriptor]; + }); + }); + } + + afterPass({driver}) { + const args = JSON.stringify(fontFaceDescriptors); + return Promise.all( + [ + driver.evaluateAsync(`(${getAllLoadedFonts.toString()})(${args})`), + driver.evaluateAsync(`(${getFontFaceFromStylesheets.toString()})()`), + ] + ).then(([loadedFonts, fontFaces]) => { + return loadedFonts.map(fontFace => { + const fontFaceItem = this._findSameFontFamily(fontFace, fontFaces); + fontFace.src = fontFaceItem.src || []; + + return fontFace; + }); + }); + } +} + +module.exports = Fonts; diff --git a/lighthouse-core/test/audits/font-display-test.js b/lighthouse-core/test/audits/font-display-test.js new file mode 100644 index 000000000000..29790271312e --- /dev/null +++ b/lighthouse-core/test/audits/font-display-test.js @@ -0,0 +1,93 @@ +/** + * @license Copyright 2017 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +const WebInspector = require('../../lib/web-inspector'); +const Audit = require('../../audits/font-display.js'); +const assert = require('assert'); + +/* eslint-env mocha */ +const openSansFont = { + display: 'auto', + family: 'open Sans', + stretch: 'normal', + style: 'normal', + weight: '400', + src: [ + 'https://fonts.gstatic.com/s/opensans/v15/u-WUoqrET9fUeobQW7jkRYX0hVgzZQUfRDuZrPvH3D8.ttf', + 'https://fonts.gstatic.com/s/opensans/v15/u-WUoqrET9fUeobQW7jkRYX0hVgzZQUfRDuZrPvH3D8.woff2', + ], +}; +const openSansFontBold = { + display: 'auto', + family: 'open Sans', + stretch: 'normal', + style: 'normal', + weight: '600', + src: [ + 'https://fonts.gstatic.com/s/opensans/v15/k3k702ZOKiLJc3WVjuplzA7aC6SjiAOpAWOKfJDfVRY.woff2', + ], +}; + +describe('Performance: Font Display audit', () => { + function getArtifacts(networkRecords, fonts) { + return { + devtoolsLogs: {[Audit.DEFAULT_PASS]: []}, + requestNetworkRecords: () => Promise.resolve(networkRecords), + Fonts: fonts, + }; + } + + it('fails when not all fonts have a correct font-display rule', () => { + const webFonts = [ + Object.assign({}, openSansFont, {display: 'block'}), + openSansFontBold, + ]; + + return Audit.audit(getArtifacts([ + { + url: openSansFont.src[0], + _endTime: 3, _startTime: 1, + _resourceType: WebInspector.resourceTypes.Font, + }, + { + url: openSansFontBold.src[0], + _endTime: 3, _startTime: 1, + _resourceType: WebInspector.resourceTypes.Font, + }, + ], webFonts)).then(result => { + const items = [[{ + type: 'url', + text: openSansFontBold.src[0], + }, + {type: 'text', text: '2,000 ms'}]]; + assert.strictEqual(result.rawValue, false); + assert.deepEqual(result.details.items, items); + }); + }); + + it('passes when all fonts have a correct font-display rule', () => { + const webFonts = [ + Object.assign({}, openSansFont, {display: 'block'}), + Object.assign({}, openSansFontBold, {display: 'fallback'}), + ]; + + return Audit.audit(getArtifacts([ + { + url: openSansFont.src[0], + _endTime: 3, _startTime: 1, + _resourceType: WebInspector.resourceTypes.Font, + }, + { + url: openSansFontBold.src[0], + _endTime: 3, _startTime: 1, + _resourceType: WebInspector.resourceTypes.Font, + }, + ], webFonts)).then(result => { + assert.strictEqual(result.rawValue, true); + }); + }); +}); diff --git a/lighthouse-core/test/gather/gatherers/fonts-test.js b/lighthouse-core/test/gather/gatherers/fonts-test.js new file mode 100644 index 000000000000..754d2859da19 --- /dev/null +++ b/lighthouse-core/test/gather/gatherers/fonts-test.js @@ -0,0 +1,100 @@ +/** + * @license Copyright 2017 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + */ +'use strict'; + +/* eslint-env mocha */ + +const FontsGatherer = require('../../../gather/gatherers/fonts'); +const assert = require('assert'); +let fontsGatherer; + +const openSansFont = { + display: 'auto', + family: 'open Sans', + stretch: 'normal', + style: 'normal', + weight: '400', + variant: 'normal', + unicodeRange: 'U+0-10FFFF', + featureSettings: 'normal', +}; +const openSansFontBold = { + display: 'auto', + family: 'open Sans', + stretch: 'normal', + style: 'normal', + weight: '600', + variant: 'normal', + unicodeRange: 'U+0-10FFFF', + featureSettings: 'normal', +}; + +const openSansFontFaces = []; +openSansFontFaces.push(Object.assign({}, + openSansFont, + { + src: [ + 'https://fonts.gstatic.com/s/opensans/v15/u-WUoqrET9fUeobQW7jkRYX0hVgzZQUfRDuZrPvH3D8.woff2', + ], + } +)); +openSansFontFaces.push(Object.assign({}, + openSansFontBold, + { + src: [ + 'https://fonts.gstatic.com/s/opensans/v15/k3k702ZOKiLJc3WVjuplzA7aC6SjiAOpAWOKfJDfVRY.woff2', + ], + } +)); + +describe('Fonts gatherer', () => { + // Reset the Gatherer before each test. + beforeEach(() => { + fontsGatherer = new FontsGatherer(); + }); + + it('returns an artifact', () => { + return fontsGatherer.afterPass({ + driver: { + evaluateAsync: (code) => { + if (code.includes('getAllLoadedFonts')) { + return Promise.resolve([ + openSansFont, + ]); + } else { + return Promise.resolve(openSansFontFaces); + } + }, + }, + }).then(artifact => { + const expectedArtifact = Object.assign({}, + openSansFont, + { + src: ['https://fonts.gstatic.com/s/opensans/v15/u-WUoqrET9fUeobQW7jkRYX0hVgzZQUfRDuZrPvH3D8.woff2'], + } + ); + + assert.equal(artifact.length, 1); + assert.deepEqual(artifact[0], expectedArtifact); + }); + }); + + it('shouldn\'t break when no fonts are used', function() { + return fontsGatherer.afterPass({ + driver: { + evaluateAsync: (code) => { + if (code.includes('getAllLoadedFonts')) { + return Promise.resolve([]); + } else { + return Promise.resolve(openSansFontFaces); + } + }, + }, + }).then(artifact => { + assert.ok(artifact); + }); + }); +});