From 0cf2ae4fcedae025bcfbd0404ac87eb6f5f2aa1c Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 29 Nov 2018 22:59:38 +0000 Subject: [PATCH 01/48] Update _config.yml --- _config.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/_config.yml b/_config.yml index d4916414195c9..52a9efd7c4625 100644 --- a/_config.yml +++ b/_config.yml @@ -3,13 +3,14 @@ # # Name of your site (displayed in the header) -name: Your Name +name: HumanEquivalentUnit # Short bio or description (displayed in the header) -description: Web Developer from Somewhere +description: # URL of your avatar or profile pic (you could use your GitHub profile pic) -avatar: https://raw.githubusercontent.com/barryclark/jekyll-now/master/images/jekyll-logo.png +# avatar: https://raw.githubusercontent.com/barryclark/jekyll-now/master/images/jekyll-logo.png +avatar: # # Flags below are optional @@ -21,7 +22,7 @@ footer-links: email: facebook: flickr: - github: barryclark/jekyll-now + github: instagram: linkedin: pinterest: @@ -41,7 +42,7 @@ google_analytics: # Your website URL (e.g. http://barryclark.github.io or http://www.barryclark.co) # Used for Sitemap.xml and your RSS feed -url: +url: https://humanequivalentunit.github.io # If you're hosting your site at a Project repository on GitHub pages # (http://yourusername.github.io/repository-name) From 6afa3b7838a929e914bd62063b5cff9eac5ed057 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 29 Nov 2018 23:02:27 +0000 Subject: [PATCH 02/48] Update 2014-3-3-Hello-World.md --- _posts/2014-3-3-Hello-World.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/_posts/2014-3-3-Hello-World.md b/_posts/2014-3-3-Hello-World.md index d4665b6d18e9e..5a8b34009586a 100644 --- a/_posts/2014-3-3-Hello-World.md +++ b/_posts/2014-3-3-Hello-World.md @@ -1,10 +1,14 @@ --- layout: post -title: You're up and running! +title: Jekyll Now blog up and running! +date: 2016-09-11 +tags: [PrototypePost1,Other] --- -Next you can update your site name, avatar and other options using the _config.yml file in the root of your repository (shown below). +Keeping this post so I can look up how it works. + +Site name, avatar and other options are in the _config.yml file in the root of your repository (shown below). ![_config.yml]({{ site.baseurl }}/images/config.png) -The easiest way to make your first post is to edit this one. Go into /_posts/ and update the Hello World markdown file. For more instructions head over to the [Jekyll Now repository](https://github.com/barryclark/jekyll-now) on GitHub. \ No newline at end of file +The easiest way to make your first post is to edit this one. Go into /_posts/ and update the Hello World markdown file. For more instructions head over to the [Jekyll Now repository](https://github.com/barryclark/jekyll-now) on GitHub. From dd4f2338b85a8d6c6b25f31742a5101140a4ec99 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 03:28:16 +0000 Subject: [PATCH 03/48] Create 2018-11-29-Arrays-index-zero-or-one.md --- _posts/2018-11-29-Arrays-index-zero-or-one.md | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 _posts/2018-11-29-Arrays-index-zero-or-one.md diff --git a/_posts/2018-11-29-Arrays-index-zero-or-one.md b/_posts/2018-11-29-Arrays-index-zero-or-one.md new file mode 100644 index 0000000000000..79e452dfcfb43 --- /dev/null +++ b/_posts/2018-11-29-Arrays-index-zero-or-one.md @@ -0,0 +1,103 @@ +--- +layout: post +title: Arrays don't start at 0 /or/ 1 +date: 2018-11-29 +tags: [Programming-General,] +--- + +Programmers argue about whether arrays start at 1 or 0. (Read more about which languages use which [here on WikiPedia](https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(array))) + +I had the idea that this is not a fact about the array, +but a matter of choice about how we discuss it and use it. +Spiritual people say the world is not separated into many parts, +but putting names on a bit of the world makes us see is as separate. + +We see `A, B, C, D` and it "is" the same thing for all of us, +there are four things and we can count them either `0, 1, 2, 3` +or `1, 2, 3, 4`. + +When we talk about the array "starting at 0" that's what we see, +when we talk about `A` being "the 1st item" we see that instead. +See it as a *choice*, and then ask "why not make two ways to access it?", +a machine way and a human way: + + $array = @('A', 'B', 'C', 'D') + $array.Item(0) # -> 'A' + $array.HumanItem(1) # -> 'A' + +The language need not choose, programmers can choose. +Then you can walk it either `0 to N-1` or `1 to N`. + +PowerShell arrays start from index 0, +but PowerShell array notation `0..4` makes five items `0, 1, 2, 3, 4`, +which is one two many. The array offset choice and the sequence notation are not in harmony, +so we often need to write the adjustment `0..(Length - 1)`. + +We can't change `..` very easily, but we can add a HumanItem() method to an array, +and pretend it starts at 1: + + PS C:\> $array = @('A', 'B', 'C', 'D') + PS C:\> $array.Item(0) + A + PS C:\> ,$array | Add-Member -Name HumanItem -MemberType ScriptMethod -Value { + >> param([ValidateScript({$_ -gt 0})][int[]]$Index) + >> foreach ($i in $index) + >> { + >> $this[($i - 1)] + >> } + >> } + PS C:\> $array.HumanItem(1) + A + +Then write: + + PS C:\> $array[0..($array.Length - 1)] + A + B + C + D + PS C:\> $array.HumanItem(1..$array.Length) + A + B + C + D + +You might guess know what's coming - +[Prof. Dijkstra's essay](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) about sequences, +where they start and end, and why it follows that starting at 0 makes sense. + +And, he remarks: + +> _Remark_ The programming language Mesa, developed at Xerox PARC, +> has special notations for intervals of integers in all four conventions. +> Extensive experience with Mesa has shown that the use of the other three +> conventions has been a constant source of clumsiness and mistakes, +> and on account of that experience Mesa programmers are now strongly +> advised not to use the latter three available features. +> I mention this experimental evidence —for what it is worth— because some +> people feel uncomfortable with conclusions that have not been confirmed +> in practice. (End of Remark.) + +And that's from 1982. + +Seems like `.Item()` vs `.HumanItem()` is a bad idea. +Not a choice I want to make over and over, and prone to introducing mistakes. +(Thank goodness for iterators and `foreach ($x in $array) {}` +which takes care of the most common "go through all the items" case). + +[Richard Feynman](https://www.youtube.com/watch?v=ga_7j72CVlc) was taught to separate +things from how people talk about them, "names are not knowledge", +but too much of that and you won't be able to communicate with people. + +Which might be why "there are only two kinds of languages: the ones people complain about and the ones nobody uses" - Bjarne Stroustrup. + +And why there are many LISP dialects and few Java dialects. + +Put up with someone else's way of seeing the world (along with everyone else), +or make up your own (which nobody else uses). + +The common suggestion "if you don't like it, change it" rings false. +If excluding someone from a group is rude, telling someone to exclude themselves also is. +Being unable to change something hurts, but being able to change anything +risks people isolating from each other, fragmentation, and loss of coherent direction. + From 8d92d00ae22b7f155423cb0ad6393057bc2d6c0f Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 03:33:55 +0000 Subject: [PATCH 04/48] Add files via upload --- images/2018-11-30-SoftwareWorkingPerfectly.gif | Bin 0 -> 38368 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/2018-11-30-SoftwareWorkingPerfectly.gif diff --git a/images/2018-11-30-SoftwareWorkingPerfectly.gif b/images/2018-11-30-SoftwareWorkingPerfectly.gif new file mode 100644 index 0000000000000000000000000000000000000000..680c60acbfa8734e8e1551031782d032edea3486 GIT binary patch literal 38368 zcmdqJ2T+vjvNk#(8ALJ+AUO^}aug(IBuE?($qX5h3?ez_JVPGRkaG@_GYTp>NY0`l zN)Y9aVXeLPxyQBseebDLw{BadR!#9S-ETkrbobl+DJm<7h?-TS&H~N=-vu3m5EC5@ z3yT;Vn-m9!>?SS_5ivC>DGezp9XSO(1(4x34GS$51uY#r9X*JVotv43n}wB!m5rB; zosW}Ckc(TGn}eDAj>sJzQ663~K0a}NfxAM&Qo~C<$ll)Z$rE=E z4-ao|Zyz6@fPjFIkdV-j@X+vRq{PO?CM6{$Cnu*peVO)bG7Tx&#p!`B)6>&40$xI) zP*~t33#p32P3%#N7KiF}ollam|uIxjD;F#b(pVPQ#02?BvAD=Vw4tgNbSt*)-F zt*x!AtE+G5Y-ng`YHDg}X=z1DTUT3KTYGzZXJ=ecJluiwlqzL{H| zo}QkWnVWmHJwHFcu&}U*l(*|kGgC`QS>0S-US65sU0GRKMauf->gLYc>c;xY-a1mY z_cq=hZmjNatQ~A@Y;11qZz5%DZ)@#fYinzJ{cwACe+Mah?{<;0f3&xKxVN{rzw>T? z?`R(>2k#FK-W|LHWkIAc>Q)#UXAdEkRMMS|BV z!|=&fvXpA!1JM-xc1y#x1w-+4vQgB^b%i6zY!AweM_es>V+qh@Vnh?H$1+8p>@SVf zm%PlC3dXs;a8fjwp~Oh^aI~THb%|zyO16q%(Nv6*4P;tn(t5huv@hzmYE#90kv^}_ z(>eEd^UW?BquHv>PLmC!&93i8XRF>m54eF#qegybtuKO@!(^PIY;7=sQ8h=c^`vJg zjo*G{y!E60c#do|je1*y(q!?2a+8S#{{5L6i?N({XM*n*Tb>*^+4(lVf7>0Le8|<& za=bB&PNeaoqxIv=n7z+3NAl&zgSmQg$ki#C&JndUw71zS3 zCG}0i>B4qb!Wq&a3?585i1ny}qT%&uo|SF$7=f9Lg&3i2#D=xV(e6fk>?f?v1UU>A z%S0s>?Ab&Wp*>4)MRnoaFbzH1qWfeD1`mV4CVN}y7tkGo5T`)fZ78)U8*RE3d~Z9G zsI>KMicYWXPWFuvXub(XW8_Y*&HnssUH}xJRvZk(qf- zZ{P<<4*S+ER_Wx>FGrn4^lcD$x9cKT7ogn3z7>UBZK0cT-u^>x3Vl{$FPn zj>`bWPUi7olj~uv2l+Ej*FMJdEaPF8k}Qf*T<`UhF`l8r6AFP@hmR8?I~5;a+&w$| z_)-d!>vU3%-0^fuiM8_dm74Io)7P4cT<$OU^c_D<8`yk3u~oOd{qc=yIM?Sn%XG)j z^N^Ct&kOf`-+f*LKbas|%BgWYTlU(iJX`TQyM8D9#toCZWl44F>)BcaYt{LBjBrlN zYQl4M5iPxF)7J4go2rZLEYG9X?Zoh$Pn)v3j;&a_&#Er>E1Hik4`idceWwd?nLqC7 z^;La2>Nq?4vQm%v++B&2gM|O6^}6cnWL)^Y-()ZDBVWztM>&@t=WMFKey&iYy*ibG zI(?m8N_YNtvAgl^>*4CP&c*qik~`N|r?bybFYB7$C$D`zdyfoJeYv}*v&7#}J_KN? z(S1gv5JNrb55S4ZLt~wjz>vAmu{xh2Fl|IB{euv`fxvs*m0z044kAy zX#fO1jxrdBljsf(aQhrbo8lEv3@Hur!H#1fY6XS-G7U7YR`#vYh zd3Z%^iprzfu#*&oniWXC7pMGjFL72x5vL8dYI>(@T1!XKG@f^&x~2?SKm+5933ik@ zWqn4YACNcRcHC0$CJ6AlLyu^w?WjxKCf~ZbTOZvhp?E> zPbwO?7co7x8;65*g>h2yB=S)3XQFOUt*#Oje?a3?d>q+O*H|f%2hn^4)~g367pqVA z+y)&-I7qG&g`e-M8!fzyGHs}~F9fmTqeMs%@&kj<)JXgj#A0jdXdvOj2v$ zIUTa<4o!D2myQcMe}p+%jFX#z+UU6T z$&*+7FW&PRWsgTM&2bV8f6{lII56G=vo(A`yM09vB&4~DV=@_%t^01*D2P96ImA7I z>+7N8J`p2gK)0GcjMzlqYVmoOd`qBqw7v_R#5(~%)Gvjh!I?R4TFWZ_7F)x+NoPT8 zW>0x1Tf^4|R(|we@TN(Vp-+*I@oE)=D(={ySZEaoVsVu}XdZ;QFuzO9;I z8WQ-OD|Y;6!V~4|$9y{-JNKTpy_PU@H3Kehv0XRz`l=IDvfe$YNA+y(z3*0qYk9C? z(%K#G@8Jx6x>sy_IdLb(Iblp<=ANfRH!Fk7qw0r;j^yI2^OEO5r^_D#6x-h}b9+7a z?EK(D9xK7+=bXK`yv@&TJI(Iu-h}z>W8kB^yX4>8>+YE_MBS6vRekSjee>X;jP>cJ z@y0h%b?A`0*$~d3FJG5Ws!u{(zUikI5-#cCW)=@Qo&*R_@&B^@R7-4pM z!zqlQ25n(a6?fIE*=Gg1s+mKcFKzsDJpIQ?{NJa0;GX*z3VVH=1(6&0e-3v)Pk#nA z)9xWPe$n8oRiai;8q}++fsF{5CJ#I~3&NiZcoXiAi4w@W>)*u^OtR}eyA#;pshUpa zm^S1qPT1#DcqruD!w3OKVFI z;_o98o~mWCn(pm;-J~y75@0@S_S_Mv&VLb@*J=**cB|hN?6oO21FF0uqhBffL*y6PiL8j~>J09y5%k zIocBQ=1t5CETu_`Sbu@oH^YiEUa>wYu?rE3OLMUvr?IO_it8c-F*O)A332-^affqp zN9S=LDB@2<;!h3YKYPWWXT)E z(De>;x{025F}6VMD3FuW76yyK&^;+j8Tx|(8V z5+o9dCXyH?l6famKocoj6RGDDX)Y4!fJqFZNlb=GEZ#|M&?Hc666bsp_eB!VMIvq_ zpr)}VJ*Z)+y;ROaw}){Bd*NnrLX(d;+g&{1~6al`C|*6gME?3Ih`Rcz?& zbt}OaZ+?snepZo117ap05k)I0y z=VAEdVeRLlf(g)~G88}LDSm(vQ0C)b=0z#zhl}PXL?Zv6K?%;MUdU&FI1)1Rw!o&l>`?UUuFx75s0=GrLY$>+ZAb1<{MBJk%J5MREn)( z#r6xucCaGrvK%!rI7Fq;$*%C>LWvNJ0&hM~y{tfOzfc1wpB1ObYP6W=TC6Z+KR>!H z-&3r_23!~lE{a$v*0@B3?89{^3!w|8O#7u#m&I^OXfn8@Or`AJXc^sTu|H+`@^Mtb~WMOqsH@8K8fB-N+fZUM1mS2?$zUka`m9xW)ntUC3n%xkN7UsfJt zSJ@ASZ{d`ylvQklOTJ!KV&G=4iB&y@A@WDzIye=E3)THTrTYt2ygt==3pH&jwV&Fm zY3$29qsp`QOZ8!u$*^Kxa4n#`WDZ<~?pwp-n}w~4)8(Ddb`7rK7O!*z)pEAOdq=C? z#L8qc%h@>K#J&~Yb`7{x4KkN?Wp>qjl(jpTwY)}+t2hV>!s1TK8ZO^reldjH0iuYq zp(CnL{h&$~x9BCP#(1oB+zyT^UTJ#J@T9$Av8+0cvRSXac_gwCtX!{LR!etTb8D=| zMLa*Wy@9bk|DJD=op_VBeH|>SbQ;vEHC7YcUY4*}D|Ap(bXh(PtDncI_A_d05Um%q zZ!2qWtN4gcu4tQPMW^z9g?%InO8 zJ`FZAZD_~XgD%NgB0)V<3^=>zsaW{rvH&#|RPDeK$Ui_7K zoO6Ey0d)_taV+VQB9UK@eM%2ymIC!skIiWhov{ML-ChfwUKVNvBEPtsOTFAzy*$)? ze0Tc!$!#33{ihE%o2O>er+m(7rpM zV?3beH(-F5!oQe$SpMAPYQU6w(ERS8rSYJ3#dCh~uI=_ghmPij#X%S9p|{`;SK}d% zm^?SXA)k(+&(I;itD%6H9DnNJ5aZzm(c!SH;V872EEJRCF&A zHU^+c-x~w$>v$>+kjZ?7WKdD08?rILldqBuu4A7rH=qSij5gZ$RGR#14AetjmpvS7 zs$Bfl7^qrq_xiZMJl0(Ot1-}0^Q$q?QoAwqvoTP&HJ0(CF;KtrGVf<&VDB|4xl81h zT^iRLbMk;ZKI|0xITLcgIbbNh#IU7(9|O=I^M1Cc7XPhF-}$>uo$y=zntj49yV^w> z!bjMm9wpdLk=Nw6?9o%W-Mj8hOLm4q->yuPTir|02os3bo=$Rh6DbQMGYAO8u->G{ z;kud-o&=}@0;Gu_I2>az6wzgvYPRK{1l<69ARHjIl44Nd{PGa%4Jv{}GZfPRkk?CU z9l@s>$$}~$&FXeeC__bJycWtrHiM?Y7_{^k;44Z~mfvH_2#6J?fyzO>Sz!0D3t2K9@lRQ@#LWs>4BX&_ud=-PtO#gB+(!vZqIktjqy~a|n{C!bSNs*73T^TpZ z=)ST&J}L>pzxqXe01bc$fa!-@+yY#zqsLGH{&Wl6TQ0-&%+b;j$bONU*J>IDlX_La zyi#3ZZ(Oq`0k-#K;aChCYZk?;&GoU&n_4Svq&;%Oi6X%aIyLnWbS{T07a~d$>8b1* zZJw!2F*+A7nFZ1d~l^P)Bhg)k^WhJJuiuubld;^-^(P#oi3<&a8zA##(^$818oD0VouH|BZIy^CqrQ(N_c`69az+V= zlMt6VTIRJ=dW$dF(Rchd7k2M?&DCXy@A_Eo^PQ)@VKeWZIcL26c78pR-%Jy*`ROdj zL!NXu$NK`f`zQc=KbjPZSL5ablmR>d;D2Xa*)U9z&4i?Z)xKy7 zUYeF76y;)-uV>PVzj*yoD1mktYfX-d0;0 z0E;A$JG7pilbFx;n~qAOnP$GGG-ai-J9~ez>4g&8iKS{r>BD6I&QKLd2o_No&xq@c zHMm;%35Egu^}tP9g{(<=U(XmBbO%G8mVqIQG?7pi+snODB<6C67^LJ)BQQ9dm4@X% zvb@j|M?5H3$WHi|m07@wC`;y8Lae>uYLV1YMwCbjz8n|Y<%#w)XK;hVv|R|MMj5yj zYXAOSCOwBn9^3|`xSQ#F7TTD%!&2Seaq)?wwHXulUV-=Jr;WGwazPTFnfg8;NbhfVOF$3{9yel%&Aq5l( zbn^E_cnh&JlG*O8z`Qwvu;XaRmjm<0%lOig|^vL4qoD`2GPQe z$r4T3Z-pa@GKs84y>$IB(tITyenvzpPlz&EEnql}6lkifPA=?6@%Y4}VksM&7Y?dj zC8Gt3hbfJmpdUR#U~1kRHbWV!B#f*N2&6jWH3gVfG1 z+B@g}#W>9G9)|pBoWS}3UcYou28S}t4f4?xGXZ1@qQ&1BP$6T%2V((=bQ>0Uk_SQ( z;d0pevnuSatqeeRr!ri#2Oi5O!Y=WHMhsV#Sx76r%)HYe`_N44Ux6$TAPgV{P$8Y= z_}|RX0zgYu&cox*%5XsmxaD%?1(Q#N%LAmwA$RAr)`o5h%c*cieqcnJLBQ2=@1#gc zgGqb_4Nx97nnmo18els}JQ3M^ZmCqyrppzNrA6OhiV}>$?=3eKgk##Bl&@aw;2n%0 zsWg&C$@5tQ0CL&%N2Q2J%V)S6ShPqH>nOMYQvLA=nAI8gN=U=qsbgaJ%}@>#0Y^bU zeKU$XdUZUHCuN2cI7|m4Xe0*tGI-2;m9*fNsuZsZ#a&yIkl}c)mNiT?mP%+~rSsX1 zGl|DuPHTOJly@rcijIZ$=dw~)^3eT@<^2Kt079fY0I)XyY6Y~KUsf<~0d!-E_}`s? zA!--^bk=+{o5KWaVN~?W45wZPWMPy*;ro`@-BwB(jN%L(p#*xd2}JHQOBb(V2D6yM zSvHgDC*V4bL_Tt%lR@Zslz>e_c~wv^iYmYq!e=!`C07JF=8W7Ay#erp8?)a~)~Nt< z0pTFcfg5B1P*nz@Ag;4&&R?uhDluL^!*RdpL`jMvET&{6oNxv%Kc-iy;PpYOsH17y zOfN?&wYcNM2gsy162i#%LJ`;Xv|NqNPXw@na|88X$Nv<-2e<_wK`K7>7sXkO0YRfo znmCN81}+CTsPE+fmXbssGZOG)-BKyUGVQw=QZJJ9CL$jLputXBrG`ZmpcKN7((Q^( z$MPZ;hnH@=g#aNV34Fz=qFc@g(81y|=+5g=qtR+`N~Eqq1B9_WXzGyG0ddId+@W4t zC*D#4D#6XCUqzKkk=`-@AX>~7-c+BWDy>;)DWJ8MPCXN3hzg0! zR~Sh~dxrXz&25(pk4IvJ1mVU$P|RgEy(-#Rrkl`=CAn;;T|8Tjor&Ku@RP7nM4~;c z40KTcG{*K!C#6R>5r6`wHh+SlRod-_No@J=UeL^-+7Fz1GE^;eS2jLb`(%`K__eFV1@tBk3Buot>AT zh!^|L&NEGah5`(L5`eP`bq0Wf`~$#3105iDe)m%8$fSK8EmK_wj};Sx2zE z3r9Dbju=TY>oXFZNa=_mD3JQ$Ez=~aQh#PN=%|>S(hHWOX~GdIPdh{RLxYX}L{;meX-*xLt)nWY?m|)f@2sVh$2RJ}z*RonUV;tL|D1z`z?7ol-CWoO=u7 z-_+wnhCoWB-k<(Z59uQyx#7uGE&vX#kR==MdVdHyqe=(Xah`k}6+d?e1<^VxcdhY6 zonS3f06HB)4Yjc@e+<1@^1J3~6EVQYE2!pStg0~tv@1kyYYI~^nq&|uh(Pvcj^u4{ zA-EAyQoum!iVi3rd{9F?efdsZ8o(4c;|3lt_^!l~-+2 zXk;*%Oqg*`wr}GP;+*e=G0Jf3>qI|};~C!%{&BpYd@RNf$;^j8_V^f6?Dkqna^WzyV zJV8$LE38!}MGcyJy=A<7*8Rx>cNS89W$nzr7+@U9032%p%m5w%Xx-LLxVG%0ekP1K+ z*_3KXj_nP@qm^+J;WZxsH1nYji|}q##!^$Q^kTUd4hJ)2H{&x=fKh^$kzSV!x<^Skh{^oK2gWv2wf7E}` z<*(=R+w=eJ2meo$M1BD-WSffzS#f_KeX$t_&=Cam7-0|-Q6qkIxNd>uumaZmk*y4s zC4<_0`B*v$mJa#4&4C0qMae5AKIYLRE)7>V<@(}@KSy7JZU%Cb4A<;*!?8m_a&`i2 z(&1{EEP@n*pqFri>`NUe2}CP|);ny=r)G673q3Tf(MykY49e2%YAH_Su$bjwrd`N! z#`!i*@>5iWuYT3f4wr)gyKbS}7ELHD)y|^C00^GOo_C#{$SUzMQSvz$8rHy0LvyTm zT+3B_?!$E1_G#pKqy2gg#jL>Eisg-Jw~WOiQ)oAkwU`Wj3+EJ*S}&Ef&NEap$&Ld5w_kf~-l}rE`}9a- zsHdOG@1@`_odv;NEUA!N3J4M{8M6#xG-?H`9*?tICFmOpyt_Prqr<98#u+*-{yhA4UrQUQ3O7gro7FUR6F^^^^ zh|BkkRT=8@A@xGq6!hzgTIbexLD;` zzJI_w^oKE@MCbBC>A{})adavrz~F=tvSrBp?NpeD5D>cJnI^#mOP~zJ)JoRT^+-;+ z&tQ-OQ7vn*l9S_`r?Gng7G=@N?i}3mP@%M1@V$rrmt520Hyr#U+NQM*rUlz>BjjOtKVe=F(EM36%!nVMZad_EGS z+8eVtbEFDmz7P^L{8+uxPIpX6cDKQLIf|X|`w-gqUUR*FC@hUnuTV|as7r+hBwJ%G zTK);-Ubj2_MC(lO=>mt!d@wy<7uBNkKv6r@&R2*R-*KM+;{%qMS7t8xybmQY_eCC` zjL+5EzkQMIdl35Ic}X?*P1vE`tkt9BGfq8;qq3vE=v&cx%_mu*iYoWwT?W6VzJ_9~ zm}T8OrB$A~y}M-6PftRp=1pI+7~*5t|N60CE4snsbFN~oASy}3+~XHp>5p6);4S)| zoK0*bXxtz)ix`X^wrOqUwH9KuyDuoT;_v!<1z-8!!&gNog2!wi zii8z8VK@aJ3cktfL9Kkk7yx8@V9hz=TBwxF`lu;ukB50Qfy4GM6NV}cY*Rru6Or+D za(6ILofxD`FYhQH&SVS83F$;GiN@Y7oZ&rF4kW+&0X*CI5nL_wze2!eK3^ zfkTU1DO&hKpVbUwZMlQa;wLk)Ia{A2&-qOM^VJ1a0RVvucS_ zE(Ha3-&FJ^rKyOYLi%kJ{ngnQotE1&aY0W-_32!?{24j!9W53vjlxJ5D@Nuk)wXTO z4?>Sx+t1#w_W8c0mC&u+eg(I$#&`OBdO1R1+UN21i^J8~QThxy)jh}cZUJe!)u)6v zy=VggQZCtkzRRel%2+BSW-hz|COzIhV0i=46Jn1tDOgf7>N9xcKQ)iP}AXwEbd!8j5&OQyxvY3tp zLwjSw-}znc2+0#!Xck5K{#bxI#K@nsl;-ESQq&!#Zm^ z26S&8Qo6EwM~UfUdxlzmD4kau(}!)P(osMC4lFrxkC z9*ss<$Hm8?0T>OwXyf#BLwrH#OPVt4ns#@ic%|#Fdo2T<)=)3jQn|#ym&_%vEgsMd z1e-Fu4=o4PatT0fBRU(hP5I1948ui46-?D$NX#0TVfzb^o5oG+P(-B^u|X~APu`eE z5reQyOfi>t8LW6lTj+!4K4F=KU{NZYdGW%93z9WtTA9$aCFQJAZ)zE)K2UpXNQ`D` z0@TXTkHRKII~rhJeRdnlo|p;fh88*69qGNz&`+@zEd;Fj{|RqCoj zpBKt&s>|ZOwteb-+r%t8@zlO(e##?Q^^nTbQfE9LQzH%U_Nmpx^gY>?al?z#Bk|y! z>nkIX_Op+>ugf3N8Vk-ek9M{VW{ZDwxa`uGMZ9f0JD&V#0&gPgocMf zp%siGwo8b{XJ|<(GXUL52qAim6%bA$-A!#)%G;* zn%~uwKAYmRb=E!E>sV$gJ9Di|6TR@6q1_^cgsxHHm?6$$9(?6&&oO;evCJmWoM2(s zE;>oq$T!=Aa=$#~uPMZ{-=q+K?^*%KpThr9{EH(?Y-%MJx{x3&bQ(1S7kb&?Ti7xp zB2#Aap~R#(SvPnsdPGUt#i)n1)`w#mC4@S>lFY_J?hwi#`vyM;=6}m`zxm*A65HSW z#NR6u`=6TNZyxubegRBm59LSA1o<<5W6|;aTg~)iD!^POg#4CRKjg={fUxx&M1sXI za$O*;!>inCEEQxidJ1vf?13ROHN4dmX0;@7fKc0KyeY`5wp-%9tkVO1f)$ z6-v+T+|Nl5rz-Kr(gcl8%N9!=Qeh2tA3!o$kAv5@4C_``I{0z5D@Ts+tU_6MSw4Gb zK+H1l0EK79>R2`Vk{_%;#S`E+AG_zR@>#8|Ved8ahSFrY#r|PKm7yoK_$SAQ^Q;3z zn=mp@rG{qj>QCxZpO0p7BVV6_1S`kZM&%{@sh`44+iyA>7MXO`n-4E@xL$7?L4D79 zB_6}7y9|BKBlha`{WYE=*9Fc$YQ!z4R()Hv17bdW+J=2jt8aqtxfFB_WLpY&KY^a8 z${UD58@kC{loRAP!L#7H-b$XPhi8VC31M?&nK!4fj##naYQlP?%xl-M;udL@vf?FV zEs~@`fnxePMDFBMw#vrw95j*JJc1ZNM#g^ILiok*dV=Z-`er;nwrygRFc);)%HT3$ zJ&g?p1f-A*ur5UL1(6iR>{oh0lSTZ!R&)HUF{E>Ef5nE#Kl^NxYV<81tp^^Y(2vNA zr9nq=q-MxiQchG!u?1ujF|)b2(1-8I#(+rn3Sx_4nxzxo{&Fg3W8L(}GNgkqbB4OG>v^F(eXMUbX~x6q>9lBlH)r#Lu%$DW zLhA^JX+zwl->j$*gh0&X7{DUy4+!Q$wDhr-lW3G!RY({C{Cw!r9?>IY^S=1gY;YOY zG?DcL(l7)1SOv;c#z;l*?riwlR*`m+iV*u|qSPydl`IPkGD&S9iMEzu^w~XGfsfE| z3ub7oT%4r(LPRlAEorYXyl^5tDc#`(#YTp58M}>qK-WA}0rH}MCoLunn>EQEV}CM> z1ZZ3ObXVenAx54G>k9+_FCR&uO?607hT ztX4x!+4VE!9rBs8jCCX@AX{{m_tLdjfm6gL=VUDho@^c44x4wQ} zEFY+x<_aAvqoQx`&@L}8`=^TRZ+!EA(9QqzMA4gO61@4SOtQ%eQcm`x)y#rw;4 zE_pK{`lS9_ZSEEN;T9wJzmD=af*Z9OM;md{4@W8<3hq~oxxF7TLO(lE2Y)CVPYN#h zHsDPFF-Jt)Xh`8aKb}gv2h?ve*0I@~$nySnm-_YN-5(%! zCth<(*Eo8gk+u7NHdBt$W41b}`ZPk;WqTBZyv@qVvQY8s5c&!WSX~*#PDly7ETWcYV z;0a@0fh2x4DA1I$LhFuWxw%IiuRwDFw^mcxWAfbuqDh4x(KpPyb6eZeq?#u+(VGi% zVXr*Za81!ldYNcjl*-csw1(wPv(LqxeS*N7fR-mAgTJMR0iR(zgL1CC{`{V zcXYW|S+@-M#5;6k&Bxr1tUNn zGY^OF-D@bm#AwGzJ?n6WxZwJ!^7l#_Su*`)aZ}f90H_-Tb*w_6=PQ!Av z+i`+Mf}DMg_Vf3*RLIMh>S&rNH=}sA9wPj2d2mvk-+3Km_#j8%u5O8GtTa&Zp)rx` zNN-YV7uscut9AD+c8hPuB#8C6L}ldS=66IO7dQQ3x)sw4_0B=MMxM@2a0}1(Prodd z7`-*$AakAQmFW3mjO3^@C7yJqZFg&C)b{l4^F*c+w>)p_gtThXB`@1 zeCCjpRCpo#cJVupAQyWvu!x){nORNcdzU@Zo?zZ5p$?u9+$BI8rk`DMzp0J276dl) zq6_twF3eRSNI{s%vDkU7KO~scH?wN4@SKVwn!*Z*wU!Q`kOj61Cd81fLEthR#a`=) z*f(tnLRD4_%wv^VE;f_y^Ucp&Njq-ND?QLwE=p7)^4`d}S&D#5Kas;uOttY5ElM?l zGi9W4geq@m+bLk%q&k8G6r^upqn0&lTVg>jvieW;<%83QRATR_%H8rAL zl;&}{S#aM2r#m-Utc)#R80G=7JbyfInQETqHO~xH1hH?H6Xz^g6%fsYSX487#o<)y z#kW5+liU}i4!i-Pn$qj%O`{8jkg_F(Q+Gk;9(za#Ya74N#(fuxak=f#V#gJ6Bs=n1 z$Wf_rTF@!Pw)246oz$e+sNqc=F5%-Vn(}vshGxEWEzanEhb?1G94<2d1fT!W(&IOb zg7HU968I0?ARqm2NSIG37)fG6t}wU0+N?~!BVPA?QdusZQhdDui3Ft#UaRf@4hhrN ze<0zYFVL9ST9;y`+_2UFTa459vx7mH!+g`H(MG3*)+Z89g2SY1_d6b3V|?%`&ok}T zz_lLmCaTr%#dN3fxN0~yjrC`JV7*TS*?gIK<6c9B=&4p-40Gn6NXX&x<$T-RWcvlJ zeTMtdveMW|*H@~RspbLaF+nF%N7sQdX#E>sQtt8HR}XNwv$I)F^C_EMuiw)Uomfq7 zj67rF67BSf$&e`U)A;!Q{@E!rJm;PW4r9!ftU~OE3VA0X!_gEt|ur4kr^g`L{B9Itct$bR8Vs*-Gn?)5he09&j~Mt zg2d1OQDBq7EgMFh>FqeHs8bf$69!x6WIH_pCLeQu!*yxTGPe>d!=o0~Z1GBEEw$(z za+_ybbtBf^T0{%xelqTQ5WnQxAj??7nFjMxfB5L@(y}HT-5{fB?;<*7f;Tula!o6g z0aX#l3#;KTwmb-{Tg2ozO@_>s(hTTj+$yA-KynUM9eSCX4U!W4b*97AX zj=FT?{y9|h8#n#mfx>_K%YRIRes9P|{sWB+MBgH0d4te0Q;hks|IfEEm`tOJq>;L< zo>+eKLAAX)LOu-mfp4jl9v$@}^AlaJK%| zM3_5-ta7o|>SmMUml?;|cEf{xW)Qi(ehBTE|INE3-7!HS=nuFMf-Xb-QKd(l_6Cs6 z9$DHOVSb`z+j)MXp8l}&$7@qL(y#AAfIn#@N4>r2-Gb$pw27ySy9*UwTc5jNXWX)F zeNUq#x~RNQa(b}iZXR5DPsAIC5~mn0i>VI7J2|dP{4Z;|KdkHD7s?X-s_{BSw|(fs zu=vG=gzDQNXMTi5#_loeckn<~1F>WVs0`SipNs%mR!*FTVebNG1E~4T@1FYp&lnVT5N*g8;#qu=1EldD@g^SI|J0NJGj253LbBgL9n^nAcsS=YZvjjGCvauNQX*Mi-Md=t5wcD~f zIkqL)4|~0KvgD2wt#g^IN_X-c>I_R#U4#U}VFc4qwj2QyY!*4{o@R#pAhIay)F2ji zR(YLmQADOM5e}PLg_a&mu^()7tK3U64mJtT3mdg7O(5H+wND#iB`QE>Nmj`jt|~UE zv1FNhS-Ccg9Pb*UBSjeWfkA={a&!03^*jm4fU`18RvcB$9=iQzCT$XIn{7`Y z9^`k-o(MT5o?eD>w;yAWJ1ODyhF0p4ee=!lI(K5b{bYgOf#><*H*4;O;oIc58*Q=Y zkNTPLmzR;7D(myZ)@}(BPbL#%MX7kZMojT^bQ|Iz|zq)(=-#B%d zZV5V-^+UFVwdrblOds_Y-8F+62v-j2!3T$hW}+cJw*#`Ohn1EeVVz@VYeQ8SoeWoV zXWV8fn7B0DSxu{Yy*xnj6=k;q%@IFFef;i^eAX>I!LD*w7w^m`vQ#ti7hFngroX?` z;=5BLUuyA|lgfbGd0B1V?vo0&*PBMPkr#sax=yC`&!HS#-#X4@_SCPfvpMRyKj%h2 zcy^t>kDO$!S{u4i6e-r}ll4yGgy0R82G&JY@yiZu)1kk3cmG&@(pTG)#mRQaH60QXmLNWh*O9O0?$b8sALftEsMF*MQCUHkVJKR2@<4xVzQTy@zgTv03Rk-h42KTKTmEM07ztb_% zw5ZvEQ4;;3=VtJiJAH&N+u!%^l=;?FuW&UlRg=3rEVs~U=*)W1raQQH8%OSDkK+95 zZ~yO<<-e+ijDHOG6t@}FS{@h3!~=i4?uAJqo{cI<0J+tLylBySks)!rWR8#drX8>amp1me#Z*Jfx1`N>xy7hiXT>pnqBILEcgeX~KRtp~hnoIkH zg(DfV{j%W3^(m*ApdLKsX_Lno*Z^_w2rX z&TTeCZ$RUZ zg@OjWN%q>Bsj_8Vj;{_`H8`%#O~#NPH%u8~Eu&f}h^gpo#=6}$Of$s$3Rz2_U}rCo z5u1tFNX1sSC5Q&E3^U3ZI9)KO-(B$9N;iSqZrSEL&Jg-BmO`yy56MQDlf~7 zW3wb#Um9-bDCz;(aw5{g7cyBwBO&?TE9~2OHz%|#b>-3f=pfsX-pVGHXm;uw6y`i#A4RZ5b?~s0wwF1D@-HQ&!x1G|OV~ zV$k-Wp?>rNk*2+{f6!QRVz*s1RHeMGy&OkH(z4BvYThPVIp(A^ZRJVrP6UT&8yu{2 z+%Z}o@LhMKcWQZPNVX=Q-tNcTQQh%vWA0p|4GcC%x~jbv|~p@Azq%yzM-!e{s2RVB9Aw`{&x! zZwTUl2T{McChwoQhU?!DRX75mc_4)5{T)#}ti>JQ*J(14FHjN~IawXbLEeavf?sc| z$I1R%9sUbZ%b*5R*=k&LzD<>xt?pXv9*~?-lcREz&FwmORbeJ@*pr=^WuwOxZ>#-o zJVIliSv3feLg)B=L9kgF6iJTBjg?lUGLn&K=iwmmWP6NFlp*f0^=KR(Bb%OvMhtNAN7s}>FG#t28oZ#+o$b_ZCVM)m_h`Ea#Pxbj zj%Thrj+SlL7m)o_$qsGK%TwjsB^Wm!mDw-6KfsiD_}a|>t61YUZGhHDQxfEw@CTxH zSAz)@*t8zok+PU+4p$c4_9lm+&xPGKZ_#sKOr>DBPX`{N56MoIqmcW0OkyF2D4m({ z#ugIFi^Q6kG*@{4DP`k9eS9Nx?#?btwjE*&ZYdryH9s zIlaryHZ?3Rk^@>WN?ueH8>&*8Qh$G+8PS`Ac#}KIo#{}oD-Ceed3B$P2yHrv$uZRY z!YaRM&Kg&%WjabVtrgqMo(K&H%OLY)%onecJ+aeuR-M+yr08H6p{kNuPs)7Py;o+R z&~Q!T@Sy{fT+O9-OAODY7v}*UPox?9>`^012~|Kh+M^hrP8{K@+M$neesv=liZM>z zgw>o+WG`e$9=gpmx!pEd*t(jLU0XZkS6)6DcYG{s@&5u*NMafP?^{)WQ~CU2qmqAS zBYqHa0E}@cmh$Jz$CMK=#f7fCeqe{oKTEovW%MU@w5@(%=k_HMI{>N3zxJ^Hz|JVC zO;6Y(WHW27k#juIk~mB^W2Ry;*>OtD;Y-uea0A}ntHv>M#`))_UvOrIT`Q#Pu#)jj zI*1s?fas+B*2X*zFQLi&_x!Tz5Zf<>d1=)+fo^Z1g0>zCc9&1Irz(v2??3e}u$xD| zeC#K7x`Q=Ld@1fcUIT9hq5Dy^&bOdVZ@Zh2IX~I+Eq!D~(|IoQ&ItF}^@I_>_&Fj< zHTP{C+3{%Y{;c>Gb-Tacg__wtp{VDe{Wti_v$R^(=puBw4T3_j08F8u*jWo9X>(fw zhv_P%xH>$x$qD0?-l30>mUdZoXG}sQM=m!)mL8MHbg!$jkZsR7GL5ip$cfd7Sm@sa zH883X00y+cSj#~L3epO1ER(^~t>#vEx991#@x;)I;$(27-3 z3@iM-4cI+@?4698BO~knB0f5gl-$bZ88h9J*dckAUD(~!ref@f{NOh4?YxIo7i@*v zWS6_yaYcnT%69j0Y~c^nL`zDrC+K%%;e4ZrLa@RD8v?t|mF0SXOUtcTBDRtMlF^5) z;LnleP$LGTii}oD-{S1NZ+lGbply;n`8C_B1?^V~2k#%e#dr9i$J6`C+`!_gfmR=} z^pd&$JhL%TIC1$_wi3QQ_1u&DhG)l~)b~=>BF%XZYYixKkpSXoA9wY9W_Iq{cRN0- zZivD@#B5BYddc{ufX0rwoGb95Kon5p?ns9~ECj9rmBSJBhR`A#B_z3QmIZzONXA_G!9q)2$^#nfTBxGy- zmUM#T_uD}MIC4r^ob3Oq?yKXX+V`$e2?>>MP>@Ctr9tq}B_J&=2n^lbjdU|~$ILJ^ z%+M+-9n#%7loFBx@4)e#<8z+tx#!*|-uL}`e`e2~4d3-$-}tTdLs$3rh^Q&nh(n_Y zzARxztDaz_%JZquYgOACH>+)Yv6^aNAAMYHK~kn)Zh52OOm57my%N2L7DubLLcEp6 zhRA5MwoZ2i&SA_Dua zLb}W32lr@_r*az5@zt)KUix-toBalN0{v}|CRWF-b`s|cDG$C)y|k$|{UGSM&AW=) zu61ig?#hjx{kmS^TU<`(Q0Vy5C(jEJ`bl3jb0-S3qGRAyHbF*&x+#r=Cp~Z`NR-

ipw(U9Y85R;)of-%4_l(98|_BFZn&71(n3Jh8~E|Z~&SJ!u4h>cL!k75)lOM*V( z@T(Kj#V$P}8uGv)IyQ(S>`2nG&eY!aU6SfC8w zI#fx^r}>D7azrD&YU$h?`cmrE3DcVID@aOQRzNSRNoKVj^IDYfwem%vN2SafFkE<@ zEI0W)gl=nmb0MFt5`!KIpl@wkXklkQ!ti{RzWG`aSF(* zFt^jp$2s*F64i-6IScUJ4cmNW)JgUr-%>#qRLyqq!BlzHnKd3(&cjlwCM;rGs=i*T zjfc90RbZ`c9H~|&^QA>lsd=k)Bk>IuLXZ%ZI+ZWk_5L-=*cL3CVGfloh$}}6EqA)j z+iQDi&l@SRDShinC-eJjW1n?7$N<%5d5)GucwMG{=`#Pt#+v?vMIduK4j@2<5f$q+4Ci@jG+Il?=TpM41 z+^xYp|2ERvH0{&Vm|QS^v|HjIb&JBs8v@%|ne|bwGl^G3^`{?Fyuq-RU|mhcl^TEy zvH2iU6VQBcKL4t^A*BM*wDw{RNv>94qART`uIp+>7^}cAts585YI+cEH`9F|_DZgK zY5o;Hr5MijwZvE~%ws}SoP*b&*q#~&8i}hY)FmdWi2R~&+5?u1OB7*9p^L>tm=?yN zRFf8pScn>#q?kg$MzOZ!GA0?OJdTWMc7@DK5ph(ck+zHCeTj&6bI&5Clt>;2aI# zoealDGE>x2?ISS&XC%^mTsldUK^=8h{Qlq?kt-zucW#GOBCm2g8v)EtW4gm~rt6O1 z*!^~nq~Xe5fmO>D=Y4re)a>9Q21Hk@#-;+DKjzgYQLYcZ_RPveb8k3$? zqg#Hu_d7a+ZdJ8D%-OUbvfNk#y6d$ysSFznSsg0;v-!>cP6dSw$oZcR{{OGmc0c*@ ztFHOwBj34NDipX{DvY^YD#W0E_S%*P-K!X^GtObu ziR22M>BqLqC271816RA$q3i_p-B+!9COdp02*GdCz5fBokkY-}$SsL+WK$b~tUOQm*~FUMkFnSxu=4SDucPaqSv+TJ$qv2W7C5D3D$*Ip34Gwn z!z9;}t#Z4>)7ETlknU*!;Rz|{`Y53l3;h+09EHxe4jRnT-#oNA81=4jxw!L9ch_nA6G_sYrrJ&Y^rg|gk2>1TZty7W!V;UT z?X}_huZ$_?V)Jx!zR;eL0l!!!bTS_t|K&;l0uj>hKt}1jHXlMRLqhWEp1)d#&gw@E zTJ_0-+T2k4(2$vkhxW@0t}LY_IxoUSj9$uMN#sG2aO0gozwJkotP9_U;^srvq-X3u)Nwp&mSBhJ1InJ`|SzxBKa)e;5l^5PvjBkHvlL!u{!T0yaV11;E!;*VNzToNlpiKLt=ByiKE z@9QA!s_n!Xv!IEcsud6LTIQ+LcO_X=x*xUOrTFlrmkQ%~d5^&1w@bDB3ezFyUzZ`m1OPYA?61A^T3aVu$69;etf}{v6>uRp|daRAGt~ z&p`#Co)X=rgp#*#JcqZceO8+qrdaMEi zQV&^Na^WaXLypBUUscAinhsUMjgUkXuH&i{k7w7htgf$4#2}%v08e!!j@vJYRS+O6 z5P8~qOo#Hg5_2{E&c~FP499`v{5X$=@*sE2^TrCPJr)kI|L#i=lUmYir7 zuC|=ia|i$o5imkP+E&OQ(DrRC%W|t=_u_mev`J`ng}I=GXm(ua8gwWZVp&tY;Kp9H zanNa1J-d)hAzhcbv;{w+MnH;NqQER~mQ&Z+%g(nUM)4NpVYVfX%C&P+;`WZFIpOTA zjBl(VlN%pDQ)8F3eK2`akb%kiWHp;^vbG;~gHf%#(~Wq7UG?F69AbU$$p^W;_&c?G zVsxcWFGA@sg<|{p&l^X>glXjaUotVU0o^Gd2{{?^rWM3`E*LcF4gV6KOxw>=hz1-N z?&IS!r1vJ7j|+wplkO8bL}>gEas0EN=Ek39?w?%viyZuu zPyAl1kNvIu`})u55J6gL{63cT5*?}vKPJKLR|w6n4z0+vJYljo{e;}W>K&?!UzIBO z2|B3XnC39Qf2`Zh0!#PF5<9MgxP47LlM`60Bm~} zKP8xbo#IkD{|X)I_KF>%6NY~8A}IIyrTSvS+kLMk`zG{h9*WfV40-CLdGl@Cn@JV{FOow`X`ozSz!u#$PI6;{*vBI zEIQBTH9j2|^}z}s(1WssGPYO1X4paP zsmc&%8(CTrX)ndCY5R{4-gNH|UTg2J9#VREhTG5i(5hmH36N1aNE9#~Gp1@&QX{6S zp}X7hsLyjzYibx8JN%+5lDkW3RmgcvahA`^X-4;u>S)B2cN#v4TSHkp6IR^Ay`U}@ zc{qrOGc?(GE`=^q31SKvpN0NZpPdFxzm>) z!%r?+i??!aeK3Act(ec=dDR1R;DYK~Q{BtYi`c+BGrEmmgEkVMDhRq3og6_QEr#6I zdfW|rvn4fQR!2md?VE9Il3;gpz+_T^jr*pK4W8`Uob7WWm+T+Ik2*wGHzu)t%-Old zB`eG(=ra5!f-*0|Z!`kYluU(++kHSPj+=@~7ehcrMu#HjJ!~W$vUG9 zJB2zxIu;ogQ>OX^rg4t@0H$%S!vb-dISo;*QcmIk!nDXs-JCufy@zI9%&ijv%FYiy zrYrWAyg=Q61n`_NmfX&fVFsrPbEgzgdLgw5OHSO1#T=MYi<4`1*CC}vJQVBsz2sP1 zIRo3WY@oL$ubE{BZg*J}l|#ZdQzE0%tSTm3&5Om0*;yY}ESg(9tRib6R4$x@$bGJs z?yYA>=};!Lt^F!6Y2An(9=28!E-di5Nr|VX%#PIhWHq;Jr4wAS%uxRbvi`V!D|MGhbD)RtQtpZor_>s@{K28}vb^RklTDO{^&KDQX{ zZSK+V&=P^=EDA5;;UeIcfZ?5f;PIy6J6)Ig+W7whYyL^X{C869Pj7_`e(Y<1Nc#LO zA(WrC-T&grzSr0*e=EngE7AT5WZaZ~0GT*;8^muQ)A>8dNYwu&$c$HUBhNHnb`7g- z7s)A)cxbePoR-(Q(}1P#8$E7>mvrHBynOe%p;@<)r(&^;Zn`(feZRsOoG3HH^5VD> zkb^ef>Umt}sM;eTBEa2~$~-i5&9&58{?w$muv~C-CUTbvG1eGRW+^ZMvY!7T$IE5) zj&jU54CS2acDdRgAiOXqF4(?NJ<CTwxXgT?5OGk)+L!tHXT)n}cPrRHW16$j!i6N&EnD3FS@` z2xj5MIyj)59`$XGP~FJ{kU&euyhI~7->3|NV74esqjldb&9&cW&D9q*we%A=kd4jm z6P8PXMhuv(lyO>TMJg(n{@8n`{28-br z=QMa@brr#7+>1GK6#KQn^HfX zlKfY74UI%@2@RWD{oQ<$Y+ogH?^=EOBr*wg7JZgQ^~({XRk?5C}@Gmoc|Rx^(K-L$Q$R}PkrNk*KO$|<=E!uN7f!XA^jRikDQHkyDH#R8#qn7?n@@fe4)c9;3SEj*Q)z&wfS(#;er+h*5#xV>B`ixINW`l&3RJ z2ELqo513`q3$NXI5odj?S;BRw!nin5rkCk5Mhm~ks2Vaxce#4BSjf;kCxRWs{mKu^*a9eGC zIqTLjGblBj7&MVmXLp2~<#(R4Rs=MGfbtwXFTzZ-szCG}iKfLjJa-Di{{Dx{O+Gv#i6Jg|%qjUamB~C`@n_jv*<{ zB0DEZv0YHRyZ#(%_qfx#Zo&}puq@Uco4xV^zkBQ5UJ|Qq1B7a6Q)Y+!$-^d;yPj6* zgf?Aeb!c~>E48|X4IAxfKpj&FUz6G#6NOwba<-j&VpUUw{(!w^m%*LAod^4*vJK-E zE4a@WtAwKVdvbh7^33d2lKghO4WVH{=Uf%lU0ENUNQGErmHp3f`eTY9LotvB(J$= z(vw|8?1;^6v^JRLK`zuzP-9X2P-D;Xto~piUD0@QCWFvy6D7+HTk5!azklxi9~JSX zQqzfOh#Rx^Y$@*}y|%=<@QXXMO*`{D3%BCS(n-9WzJyBMcfRBGc=EmA>Yz=p+Z&JL zLN8Pj`}12QiPptLFZ6wtw(_$bYx!>u2J|2E;0N^)@zPkJ8vYQ83!$VnF4Hb2Ims!y zWA8?D!(+G57Tq}qK*T2NA47mqVLL~Q?l#LW^h086MrLCaXvmbT@kJ1HD(Uha_zA=! z655io!m5PQF347Ol8%WR%?tJGi43-Ssey#PmhP+Lsdg>Z#sT;vq1w`JE8~Th)w&}E znJy>b9AGdyR(h`U0&CgS`3_(E)s z{d!6zxI@omB4dXY9Rh2_aHph~V&t`rxCdT_IKk8`G^(8^=`p8YxokS^AB?KX>F&>9 zI=NeY>hs3HJreW0h~%Dot~kv*6R>eBb|id{>S#RDW$S1-`67~QF_fT=YkbBm&}G(N zpWRi=H!G@sKDBt;eFEGdT(eN5;?2DkL=Yv2D6lBy-GcZ`pR6~&Q8?Oaj=pu`_KQW~ ztic!VJL8^*j~<>G%88XZj*kxhPTjvJ#?!x-7%TFSXU;|ZRrv<;e)D!*ZU^3ygIzYL zkgFrt8q?p!Gj^n3dOHfJu871*UaeO#f5;T}33mL474l^`LUh9`UW&ny%Zf&F@a+$N z4g@V~$(P=a=%))#W5^1*-i?fy-Lv-5L|x3RKqeHHKlN56UU_Cp&7p$~joX3RtLC0g z3WrSb%E_^5JE-{8EBTVW8ioE!2kdFgVJEBUw?Kx1NWogWq~}Wa*}RbgcgP0Sm2lcu zq_?B~6b0WSm#w+4_!o4PWDZArp7dhs5zS|=JD(dkouivPJqPy?D)3EpyS{HH604fN zC-b~SGWL(8vK>m!R>jR(v-S z8?PiANFS%@K3pKG`M9Pa;g&&%QZkXqOG0Tk8prTNGB2{&bbD(xfSQZ4Dj@TL$jdpK znQ7-`F%yQNvGj+{QopCj+)c>i%^(xR4t%6+GK{DeX+)S;gB3s8y0 zV(Y{5`Z2hHDE>johtH3@cDgsn<@Q<`89jG0%nwG^0c3j2kXGYPmeLLhu`avZ?A~tr zqB~*{W{~|ED92!gNrqYL^To}tQ72kfM9lzle(o%zJM>PnW@$Z|238I7WbusN@YHG9 z-DRpsxl|w>Fv@4OXV}vfgXqYaZ{Y0te8e=pvqHjh93GE~cc|Hnu2f_n zhI&VLYfJ!+E#_m|r32gaHN_l({hgmne z$Gjh%-AVD8`L;L!zs>LQQM-(EIr9!??aZf#xA6{!y1Yo|2kzT6zsk{gBOD#lHFJ0x z|Goe9)6(>(7yg0||D(_o0*8GPeF~57tzLNYC?p!v; zIrQtlx zF?)qO-LQO}4^l|n!BKbcje}#kuRIg55UG`Xh3w1`?Th5+X?8h7P8_5Il>o>ADgmS& z+z`MytRo2fvdHPRF=a;iA92S5P)B07us!*n;6e|FxAJK34jSh{6j_r;ljo#|{x?0O zp9S{bsFclk$wKD-mP-bp2NN`H=1{<(;fF4{nrc-hF*fJ?@m=d&VDDG-L@^RWS4uld z_v8$FWv`^P*MHy+M=OZP)kBwI(Jr9LN#B>ZvT!C!Xo2*u_aPdXBF23jG#v_k)Ddfp z`_*wE7+-08UKv$y96yn`V8sZi6%10*yV>)_7--5qs+P=Gfw`c3Q}QSylnT#<)>MZW zNMY@f$($3MBJq{NfmkbfIm09M#iW(%i8!q-u4E@ouD80TX<)6JBOu$YGXbpNPmYR` zpD7B`0>S8m7z^`hKe80QIlkZlfg!^C+4->gFbfIPW*&=-w`?pqWwBZaToj$)BLp~p zg?uv$FT)&~9FYrQ0B32PY)UC@53Ng9VTH41&EIBaDGL*Auzd z6u0c_!5Mep3~WI+T9;=+;e8uv^egP%qq(#<-U4gU7}lp-;j57i!?9W02g~rbZQP{> z3~K((kE05wyH&iiJYRaH@&&!)N}>)vrK5pf#E#iWX8D9UDW(oi@|M7kg8$zD8YG^u zU;BqTK0igLpI-P21pH2XFuw!PKTwSQlc{w87T$GSGNdHJucp?O1!8d=6mh>P`}#lO z%LDYq30$dEt#t=-`uw^@8zG!Xi*{1|>nW${&YI%U-%YK5^{yH*dlzhTxoHk7osPVL zV2CJw{(1V1Fa1f+#wVM(_pdPzxJ}1w7uuW=vccGOyR#_{WQs!Obyb?Zf_I2fx9avs z{q3S#xq93!2R_{|fMsqueU;9?X*@U+No1lL3vWyLDnH}q)E4pdKL#&D4|D!?q9#$_4j$m+kDpIvDa|utuM3!$C+M;e|2UjHDQO= z8bYoM=?Qx2Ki=f5ZF)!4HN&olA29FSEb(<9_+03NX3#xZIHj6!;%~%@Kt&)x&*n&=X-K2O=lx{GM1+!rhp+5UnSoW7n>}Supp(P#jFIB zR~}DH#&WA8OeT#TrzHO@6Qd$TMfm?uX;0^{FsFO1nro?G6fHRZK*T8vN%w}S-r5E+g z`GxD_U{JYRt%^0Zh!!Y6{oH-6Fe4brgDP7DpcU^;+&3yesGnGtS1DL9feM;Cz=b_5 z4eQy{0u-esJ>FOp&l?rSHsBpm9%gXUC=biVJ55~=ssWta$MAjn{UTkBoHa3(?De?jb9?ZW#YD^B)Y`sy*CekE|tM(Ca|oXxLxN7 z%wiYt`fNpA=gGVKIxogk1!nZ(oeJiBINxy9QmA!cNB=<1iZQUoDZgB+|eZHa4tLM23#fF_6ACXvV zEpH>TE}krsqQu(xLj7iUb3@*a|8BzZ6FT!3;s29QT&?YK|Afx`JGc8j9KijXJSVU1 z^-Y3c9B|B1+ix%<7fSbvhwJ$A>^$=5S0L$Ll42IU%axRuQsy1`>q1wX#1ua4L}Y|N zhZ&gFxc{yB%T0ii>4v))Bl1id^LmZGH?+SMkIw7Adri>x)#A$+gO4$2qZy5SmBt?! z5IlvldzGs-8F!K%ke*bTRiZ5qB)HXcYZc^5C^*S`JlH@HvICa(2wEtDE9?%bXSnyb zra#1!B-Yn2SuX!jUm<0S&m3ow7PKxGcl#=Abvn~JiuwQb6Jl)ENiZiWgEC3W>;o3ehH#&!>mYMR)?g4bj&BL^H10X9=}sNGx_{>IgXXHmFF|gdJSJ6 z6p|7x3*{V;k9$(8?jq?$(5Jx3T|KPhf+{k);WbT*YSeoOP=k;UHE1NXe?C$h=e5u~c{5IXmsEC{%=s!K&1n~+#Ihs6G@LspIQ4rek(TG0V zC5Zg&Exu~g=b6>#aogEu=Uv;W<}Y9bNlKpl zi`?fg?)H=K|99BZf8(vb6EBj#OT45a{)~uS5kDegBdJ61KSD(2e};%9lc{JFt(VIg zlMSwFx2w}^OGTUAZeWkxbS)Em8$iGs)efXF{1AR$3MQvny3_@fAK^A7p^@*-{_HLM zqH=ES6KIe)T@IN6b$Iv#Kt=wm;-`0<$R-D(D?KYp5OTuk)bL-&Qr>h^tBY zz2k&L#3rQHx7S_Xiv#TDCsOb2Ssi%#nqL|C&yT{hqAMyqdzTO!fGPOX^Pp3-o3SQ# z{09U^*VkQA?J;?3wE&#MA72J+c1TXy5-7jWL(2RW<@i@)@(zYz(yl%arn6t2dX3?h z{0AZ~M)H{hv-H!J+o{}rz!+K4Pqi56{KX$*yz>&HPN8#_yUo1pdaR2fl2E2=HWZh7 zYt2wn!<<9&|VSds)1dt z70CEHIZH8eFL=AgFiLB+sDQoRqWV=>*S7eSY^OyrlwEp4nlXdCG;R7^piIPJXxsw6 zCO~LWw4^7x0VbWrnGk8bYxrrKN)` zjaE?hi__8%oLxG5Z+88mY>nH&lvNcnk%13or%s+#weApSJbxP&RlnCG+o!|v5y!)V zyGAHFq6+CI>Qy~(lca&xrY7`eQJE>l)aFN)wDsb5NSo=eUG$va4xsQ6uNtUl@zlwe zi2xo;PG}2qOf<<8yuqETZ+DjS7EjE{MLp_ihwgF`;I?*RvRx@bw3E_Eo=2V-p+LM2 z&D!y5fr{$bI{v%!=ZK;Ul7@uZQ$|4_A|Z6*IQeTnrv`%jnD=7d=Lr{l>A*14cg?%Y zKdLua#_nY-B!J$ur)sY!=sl+BL%MbccJ8^|>tGXm0Ly#YaI#CIICebbbCLN?zVad6 z&Kg)_&b>KYG5#B;;2A=}Bj;5A+jUd2>sWVGw(rlN9JUE!9w<7DDCwRihrH_{`s7Tx zdCwgGX7hIFbAkUi4vzfmz=gyov7ZpYpCac^FZ}PI^Pe91Z*98#?>yOe`b+({>2LIZ z0{i$M!G8ZI^q2deg1t8U53slT1MDR+zk_}2cd(Zeo`UbrB8?qXwkSr~MN?D7Fwniq zjYI}=RjSzdfQ8S7%RjTQvDuq%PFm<=tkqF)Z_gTd$QCpq_g^dXolb>&ry#1M^j5r= zzATsHh3{ZL_weL`dkt=Vw8wI*tEP*(=`=nF)1Kj?S-7orpI;2tr*C-r4I6E2))zm; zDAN=5top9sja(RI0B-N-#4{%$QUk9lBB}HslKLVY#{s9Ymsan4=nMlp_&>~t&I$n* zL})6JRW_3TBEfzIv>3G-$#~CAco&r6?sFEB9W(P0u;eejutMQ2MLtgFps3|cr~8bD z^p~Bq*b)DdF;Sc0uG~7JTvy6i~Ol=&krD@et4A)nKRlJ-TK@JluxdjFGE`asUYSQHPY;f`^G+xWZI$l`3nA z!-P@4P4sKCIOkL}sQyKgwQ4><4H6FwXYr$Xd?9w%d0nMa+$AZQsMzIbhrnZr495IA zkt__{6ER#|w*q4kEh9JavNxrPn~MDkv70cs>d|)o#n$O^t{5F(!pn0I-gcG>JOAhW z@Tj`aeZU#qy~3yZXG=YYrQZ;va%E=+jak$lyBQCk3Vj*RQ)oT}71=cHA+mgy7ocUC zO1tkKDthg`>AJ&zup_8{k$m{{oZrY}d~$XlMf#UbM4wla;LB5gl3y@e`W%T2?xEjk z7dqZ*dvvoCe=cHA`2nX)SNto+m`+aB4e}Rig%#!^VsqSCg?O%oY z|JGam>8Bv!_a@E%r^@3s*RBJW0; zY+Pz6hdI{T{kkxn@WTE|TR;-^mpx*6luK=ajz61h{7GBjv9{r~tSakh*;DL^2RC7s zy>Wa!kjPNy5^W&;YGX$D07DN7FJc{y?1%jkAEae14$__)<)$Udjhlq7#V>vR;pi++ zkOP~RV63~MbbNN%A3{lJOdMat8n#7Zi%4#^m)}Q?K*x(iiVb8nB6V)7^ORpJQb_9ZsTmCWX`rd!!rCwT?umIdxdNaVqufQhLZaME zKt8~gYpx$0A6?pYBl~^GO&VFxT0rhc|632uyFvZ5ZBh77{XLnGW(IK#j|u}{+ZVh| zVmByFNQpC%3dSa?|EI6$MHM^RTW%B$l&9~|iLetaU*wp06>ilf0VXqSbX#@#d5v}B zU8Gi;j=0~V-MH@hyUHZ;-x7e5ft16?MLsAK@^6WH?+dYS0Qw!4XP}suVu5$4gpF!B rXeC|~u$gza$IiXw%>QlI{=YRmeiEBkmR>(Xzz=cr)9?S+E(rb~LK)wC literal 0 HcmV?d00001 From 3e370a6aafe49d0c694d09d3e2c08878a15ff95d Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 03:35:52 +0000 Subject: [PATCH 05/48] Create 2018-11-30-Webbrowsers-in-2018.md --- _posts/2018-11-30-Webbrowsers-in-2018.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 _posts/2018-11-30-Webbrowsers-in-2018.md diff --git a/_posts/2018-11-30-Webbrowsers-in-2018.md b/_posts/2018-11-30-Webbrowsers-in-2018.md new file mode 100644 index 0000000000000..3d6220cc6c7e4 --- /dev/null +++ b/_posts/2018-11-30-Webbrowsers-in-2018.md @@ -0,0 +1,8 @@ +--- +layout: post +title: Software working perfectly in 2018. +date: 2018-11-29 +tags: [Other] +--- + +![Web browser textbox control scrolling up and down with every keypress]({{ site.baseurl }}/images/2018-11-30-SoftwareWorkingPerfectly.gif) From 4be7287ead4184eb307bea59074bac50f03433da Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 06:08:15 +0000 Subject: [PATCH 06/48] Create 2018-12-01-Reading-N-characters-from-the-end.md rev1 --- ...12-01-Reading-N-characters-from-the-end.md | 224 ++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 _posts/2018-12-01-Reading-N-characters-from-the-end.md diff --git a/_posts/2018-12-01-Reading-N-characters-from-the-end.md b/_posts/2018-12-01-Reading-N-characters-from-the-end.md new file mode 100644 index 0000000000000..fe86c9f374698 --- /dev/null +++ b/_posts/2018-12-01-Reading-N-characters-from-the-end.md @@ -0,0 +1,224 @@ +--- +layout: post +title: Reading N characters from the end of a text file +date: 2018-12-01 +tags: [PowerShell,Programming, Unicode] +--- + +#### Someone + +asked why PowerShell `Get-Content -Tail` only works with the last few lines of a file, +and why it cannot read the last N characters from the end of a text file with no line breaks. +e.g. if they have a 2Gb file which is "a single line", it's no help. +They wanted to get the last 100 characters quickly. + +That's easy enough, I thought. (TL, DR. It wasn't). + +--- + +#### You can use .Net to read the last 20 bytes from a file easy enough: + + $numBytes = 20 + $file = Get-Item -Path .\bigfile.txt + + # Open file as a stream, + # and seek back from the end. + $stream = [System.IO.File]::OpenRead($file.FullName) + [void]$stream.Seek(-$numBytes, [System.IO.SeekOrigin]::End) + + # Read some bytes from it into a buffer, + # and decode them into text + $buffer = [byte[]]::new($numBytes) + [void]$stream.Read($buffer, 0, $numBytes) + $stream.Close() + +*And* you can turn them into a string, easy enough: + + [System.Text.Encoding]::ASCII.GetString($buffer) + +Which is alllmost fine. Oh btw, what's that over there... + +--- + +#### Hey everyone, it's UNICOOOOOODE! + +If you learned to code, you probably did a lot of exercises like +"reverse a string", "treat a string as a list of characters", +"do ROT-13 encryption on a string", +and these are fine for learning about loops and indexing and code, +but terrible for imprinting bad ideas about writing and text. + +They will have introduced the idea that `"a"` is a character, +it somehow has the value `97` because computers can only work with numbers, +and that's related to ASCII. + +ASCII is "the" standard which covers what letter becomes what number, +and everyone agrees so that people can convert chars to numbers, +other people can convert them back again and get the same chars. +Several chars in a row is a string. + +If you are also monolingual English speaker this is fine. +My classic understanding looked like this: + +| | Classic | +|----------|---------| +| | "a" | +| | -> ASCII| +| byte(s): | 97 | + +There are other character sets used by French people and the like, +but they just choose numbers for `é` which is simple enough, +just agree which encoding you're using. + +Then I read a bit about Unicode, and my understanding changed to this: + +| | Classic | Basic Unicode | +|----------|---------|---------------| +| | "a" | "é" | +| | ASCII | Unicode? | +| byte(s): | 97 | 233 | + +It does the same thing in the same place in the same way but it covers more characters. +Simple, useful, but incorrect. `é` just happens to fit inside the value of a byte, 0-255. +What about all the thousands of characters which don't? Like `ă` with value 259? + +Turns out that Unicode is more than a simple mapping of one letter to one byte, +it has "multi-byte" characters! +The original choices were 1, 2, 4 bytes per character, a tradeoff. +1 byte cannot represent most characters but it can represent English just fine. +2 or 4 bytes can represent most characters, but English speakers don't need that +so 50% or 75% of the storage and memory space and processing time is wasted for English text. + +Then UTF-8 came along which is "1-4 bytes, varying, as few as necessary". +See this short [Tom Scott YouTube video](https://www.youtube.com/watch?v=MijmeoH9LT4) +on the topic of UTF-8 and how great it is. + +In the Powershell world you mostly see: + + - UTF-16 (aka UCS2-LE), which uses two bytes per character. Windows and .Net often use this. + - `PS C:\> [System.Text.Encoding]::Unicode.GetBytes("ă")` -> `3, 1` + - UTF-8, which Linux often uses, and PowerShell tries to. + - `PS C:\> [System.Text.Encoding]::UTF8.GetBytes("ă")` -> `196, 131` + +So my new understanding of Unicode became something like this: + +| | Classic | Basic Unicode | Next Unicode | +|----------|---------|---------------|--------------| +| | | | "ă" | +| | | | Unicode? | +| | "a" | "é" | Codepoint U+0103| +| | ASCII | Unicode? | -> UTF8 -> | +| byte(s): | 97 | 233 | 196 131 | + +and that was fine for a long time. +This understanding is just about enough to fight Unicode problems, +which often happen when text was encoded to bytes one way, +then decoded back to text another way. Let's see a couple: + +Smartquotes like `“` run through UTF8 then back through UTF16-LE: + + PS C:\> $bytes = [system.text.encoding]::UTF8.GetBytes('“') + + PS C:\> [system.text.encoding]::Unicode.GetString($bytes) + 胢� + +Text through Unicode then back through UTF8: + + PS C:\> $bytes = [system.text.encoding]::Unicode.GetBytes('test') + + PS C:\> [system.text.encoding]::UTF8.GetString($bytes) + t e s t + +There's a few common versions of these, +and a few more when considering HTML like `£` showing up wrong, +and this level of understanding has helped me imagine what's going wrong and fix it on many occasions. + +--- + +#### Back to the end of the file + +So we don't know what the text file contains, +but the maximum encoding is 4 bytes per character, +then reading N characters from the end of the file simply means reading 4*N bytes, +converting to string, and if that was too many, trimming down a bit. + +Easy. And it works. + +It just means a bit of error checking, because for a file of 5 bytes, +asking for 3 chars and trying to read 12 drops back before the file begins. + +And it means a bit of guessing what the encoding of the file is, +but you could always just make the user tell you, +or guess, or default to UTF-8 which is what a lot of tools do. + +And it's fine and workable and good and great, but .. also wrong. + +Because my understanding of Unicode is still too simple. + +--- + +#### There's another layer + +I found myself reading a Google preview of [Unicode Demystified: A Practical Programmer's Guide to the Encoding Standard](https://books.google.co.uk/books/about/Unicode_Demystified.html) +by Richard Gillam, and found that you can write `é` as a single thing `[char]0xE9`, +but you can also write it as the letter `e` and the character +`COMBINING ACUTE ACCENT U+0301` next to each other. + +I think it may be ["more correct"](http://unicode.org/reports/tr15/#Norm_Forms) to do that. +It's the "Canonical Decomposition" which allows you to take input text using +both ways of writing `é`, make them into a standard form, +and then compare them to see if they are equal. + + PS C:\> 'é'.Normalize([System.Text.NormalizationForm]::FormD) + # this splits the "one character" into two, the canonical form + # but I can't copy and paste them here because they just recombine + # 🤷 + +Worse, Mr Gillam writes that there are combining characters which attach to two base characters. +Like [`COMBINING DOUBLE TILDE U+0360`](https://www.fileformat.info/info/unicode/char/0360/index.htm) +which covers the previous and following character. Let's see how that works... `ãa` vs `a͠a`. + +And worse again, Mr Gillam says that there can be an arbitrary number of combining character marks. + +Now my understanding is more like this: + +| | Classic | Basic Unicode | Next Unicode | Copy of Next Unicode | +|----------|---------|---------------|--------------|------------------------| +| | | | "ă" | "ă" | +| | | | Unicode? | Unicode? | +| | "a" | "aé" | U+0103 | (Multiple CodePoints?) | +| | ASCII | Unicode? | UTF8 | (Choice of Encoding) | +| byte(s): | 97 | 97 233 | 196 131 | | + + +But the summary is: there isn't any way to cut the last 20 characters from a file. + +Display graphemes (a thing on-screen which looks like a character) might be made +of multiple code points, which might be variable number of byte encoded. +In the worst case the 2Gb file might be a single base character and two billion combining accents. + +If you jump back 20 bytes, or 200 bytes, or 2000 bytes from the end, +you might still end up in the middle of a multibyte character. +Or the middle of a multi-codepoint-grapheme. + +And the only way to /know/ is to read from the beginning. + +And even if you read 2Gb of bytes from the beginning, +it doesn't make sense to `.SubString()` it to take "some characters" +out of the end. Because it might split in the middle of a multi-character-grapheme. + +Even though the preview of the book is quite readable, +I doubt I could make it through 800+ pages of this, +but it probably contains many other reasons this can't work 100% correctly. + +Which means all the things from earlier programming lessons aren't quite right. + +- Characters don't map 1-1 to numbers +- or to a fixed set of numbers +- or to a single Unicode codepoint +- strings aren't as simple as multiple characters +- reversing a string isn't easy and might be impossible +- checking if a string is a palindrome.. +- oh heck, google "wrong facts programmers believe about Unicode" there's probably thousands of these things. + + From 69c0fd48cd7ea1dc99f7ea3690b0ca5c2275adc2 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 06:13:58 +0000 Subject: [PATCH 07/48] Update style.scss add table fix from misaka-100032 --- style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/style.scss b/style.scss index 3915a90244691..eca9d7015fe99 100644 --- a/style.scss +++ b/style.scss @@ -5,6 +5,7 @@ // IMPORTS // +@import "http://github.com/table"; @import "http://github.com/reset"; @import "http://github.com/variables"; // Syntax highlighting @import is at the bottom of this file From 4bd6fd00fd0d1e43f377fdb5719c2bd22a6ab7d7 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 06:14:26 +0000 Subject: [PATCH 08/48] Create _table.scss --- _sass/_table.scss | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 _sass/_table.scss diff --git a/_sass/_table.scss b/_sass/_table.scss new file mode 100644 index 0000000000000..554ad805fed95 --- /dev/null +++ b/_sass/_table.scss @@ -0,0 +1,25 @@ +table { + padding: 0; } + table tr { + border-top: 1px solid #cccccc; + background-color: white; + margin: 0; + padding: 0; } + table tr:nth-child(2n) { + background-color: #f8f8f8; } + table tr th { + font-weight: bold; + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr td { + border: 1px solid #cccccc; + text-align: left; + margin: 0; + padding: 6px 13px; } + table tr th :first-child, table tr td :first-child { + margin-top: 0; } + table tr th :last-child, table tr td :last-child { + margin-bottom: 0; } + From f017b8e3318780a3928b06868a250887bfb54d28 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 06:17:21 +0000 Subject: [PATCH 09/48] Update 2018-12-01-Reading-N-characters-from-the-end.md fix dragons --- _posts/2018-12-01-Reading-N-characters-from-the-end.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_posts/2018-12-01-Reading-N-characters-from-the-end.md b/_posts/2018-12-01-Reading-N-characters-from-the-end.md index fe86c9f374698..23e8e7efed7d0 100644 --- a/_posts/2018-12-01-Reading-N-characters-from-the-end.md +++ b/_posts/2018-12-01-Reading-N-characters-from-the-end.md @@ -14,6 +14,8 @@ They wanted to get the last 100 characters quickly. That's easy enough, I thought. (TL, DR. It wasn't). + + --- #### You can use .Net to read the last 20 bytes from a file easy enough: @@ -188,7 +190,7 @@ Now my understanding is more like this: | | | | Unicode? | Unicode? | | | "a" | "aé" | U+0103 | (Multiple CodePoints?) | | | ASCII | Unicode? | UTF8 | (Choice of Encoding) | -| byte(s): | 97 | 97 233 | 196 131 | | +| byte(s): | 97 | 97 233 | 196 131 | Dragons here | But the summary is: there isn't any way to cut the last 20 characters from a file. From 421c401fc08ed1daf10d6a0377e5f8bd5e708e86 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 30 Nov 2018 06:19:58 +0000 Subject: [PATCH 10/48] Update 2018-12-01-Reading-N-characters-from-the-end.md --- .../2018-12-01-Reading-N-characters-from-the-end.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/_posts/2018-12-01-Reading-N-characters-from-the-end.md b/_posts/2018-12-01-Reading-N-characters-from-the-end.md index 23e8e7efed7d0..b39ea0f3198a4 100644 --- a/_posts/2018-12-01-Reading-N-characters-from-the-end.md +++ b/_posts/2018-12-01-Reading-N-characters-from-the-end.md @@ -190,7 +190,7 @@ Now my understanding is more like this: | | | | Unicode? | Unicode? | | | "a" | "aé" | U+0103 | (Multiple CodePoints?) | | | ASCII | Unicode? | UTF8 | (Choice of Encoding) | -| byte(s): | 97 | 97 233 | 196 131 | Dragons here | +| byte(s): | 97 | 97 233 | 196 131 | ¿Dragons here🐉 | But the summary is: there isn't any way to cut the last 20 characters from a file. @@ -209,8 +209,12 @@ And even if you read 2Gb of bytes from the beginning, it doesn't make sense to `.SubString()` it to take "some characters" out of the end. Because it might split in the middle of a multi-character-grapheme. -Even though the preview of the book is quite readable, -I doubt I could make it through 800+ pages of this, +Although for English speakers and most files, you can do it, +and it works and it's fine and convenient. +You just can't do it properly quickly. Or at all. + +The preview of the book is quite readable, +(I doubt I could make it through 800+ pages though), but it probably contains many other reasons this can't work 100% correctly. Which means all the things from earlier programming lessons aren't quite right. @@ -223,4 +227,3 @@ Which means all the things from earlier programming lessons aren't quite right. - checking if a string is a palindrome.. - oh heck, google "wrong facts programmers believe about Unicode" there's probably thousands of these things. - From 95739d0a05225f52810fb04a8d2045d3a5602821 Mon Sep 17 00:00:00 2001 From: Andrew Childs Date: Fri, 30 Nov 2018 21:40:45 -0600 Subject: [PATCH 11/48] typos --- _posts/2018-11-29-Arrays-index-zero-or-one.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2018-11-29-Arrays-index-zero-or-one.md b/_posts/2018-11-29-Arrays-index-zero-or-one.md index 79e452dfcfb43..b938bfd10b6c5 100644 --- a/_posts/2018-11-29-Arrays-index-zero-or-one.md +++ b/_posts/2018-11-29-Arrays-index-zero-or-one.md @@ -30,7 +30,7 @@ Then you can walk it either `0 to N-1` or `1 to N`. PowerShell arrays start from index 0, but PowerShell array notation `0..4` makes five items `0, 1, 2, 3, 4`, -which is one two many. The array offset choice and the sequence notation are not in harmony, +which is one too many. The array offset choice and the sequence notation are not in harmony, so we often need to write the adjustment `0..(Length - 1)`. We can't change `..` very easily, but we can add a HumanItem() method to an array, @@ -62,7 +62,7 @@ Then write: C D -You might guess know what's coming - +You might guess what's coming - [Prof. Dijkstra's essay](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) about sequences, where they start and end, and why it follows that starting at 0 makes sense. From d3e86507a293747fd65c062ceb4005bd51ddee87 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Sat, 1 Dec 2018 06:40:19 +0000 Subject: [PATCH 12/48] Update 2018-11-29-Arrays-index-zero-or-one.md Tidy up some of the writing, expand on some of the explanations, clear up and focus the ending. --- _posts/2018-11-29-Arrays-index-zero-or-one.md | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/_posts/2018-11-29-Arrays-index-zero-or-one.md b/_posts/2018-11-29-Arrays-index-zero-or-one.md index b938bfd10b6c5..927f9396a2085 100644 --- a/_posts/2018-11-29-Arrays-index-zero-or-one.md +++ b/_posts/2018-11-29-Arrays-index-zero-or-one.md @@ -7,34 +7,31 @@ tags: [Programming-General,] Programmers argue about whether arrays start at 1 or 0. (Read more about which languages use which [here on WikiPedia](https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(array))) -I had the idea that this is not a fact about the array, +I started this post thinking that it's not a fact about the array, but a matter of choice about how we discuss it and use it. Spiritual people say the world is not separated into many parts, -but putting names on a bit of the world makes us see is as separate. +but putting names on a bit of the world makes us see is as separate, +and that is related. -We see `A, B, C, D` and it "is" the same thing for all of us, -there are four things and we can count them either `0, 1, 2, 3` -or `1, 2, 3, 4`. +We see the text `(A, B, C, D)` the same for all of us, +there are four things and we can count them. -When we talk about the array "starting at 0" that's what we see, -when we talk about `A` being "the 1st item" we see that instead. -See it as a *choice*, and then ask "why not make two ways to access it?", -a machine way and a human way: +Both countings `(0, 1, 2, 3)` or `(1, 2, 3, 4)` can make sense, +when we talk about the array "starting at 0" we see the first counting style, +when we talk about `A` being "the 1st item" we see the second. + +See it as a *choice*, and then ask if we talk about two valid ways to access it, +why not *make* two ways to access it? +The language need not choose, programmers can choose: $array = @('A', 'B', 'C', 'D') $array.Item(0) # -> 'A' $array.HumanItem(1) # -> 'A' -The language need not choose, programmers can choose. -Then you can walk it either `0 to N-1` or `1 to N`. - -PowerShell arrays start from index 0, -but PowerShell array notation `0..4` makes five items `0, 1, 2, 3, 4`, -which is one too many. The array offset choice and the sequence notation are not in harmony, -so we often need to write the adjustment `0..(Length - 1)`. +Then you can walk it with either sequence over the items: `0 to N-1` or `1 to N`. -We can't change `..` very easily, but we can add a HumanItem() method to an array, -and pretend it starts at 1: +PowerShell arrays start at 0, but we can fix it, +add a HumanItem() method to an array, and pretend it starts at 1: PS C:\> $array = @('A', 'B', 'C', 'D') PS C:\> $array.Item(0) @@ -62,11 +59,19 @@ Then write: C D +PowerShell arrays start from index 0, +and it has an array notation `0..4` to make a sequence of numbers, +but `0..N` to get all the items in an array actually makes five numbers: `0, 1, 2, 3, 4`, +if you want to get everything in the array you need to write the adjustment `0..(Length - 1)`. + You might guess what's coming - -[Prof. Dijkstra's essay](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) about sequences, -where they start and end, and why it follows that starting at 0 makes sense. +[Prof. Dijkstra's famous essay](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) about sequences, +where they start and end. + +From that, Powershell is "doing it wrong". +Arrays should start at 0 and sequences like `0..N` should generate `0, 1, 2 .. (N-1)`. -And, he remarks: +But, I had forgotten this bit, he remarks: > _Remark_ The programming language Mesa, developed at Xerox PARC, > has special notations for intervals of integers in all four conventions. @@ -80,24 +85,25 @@ And, he remarks: And that's from 1982. -Seems like `.Item()` vs `.HumanItem()` is a bad idea. -Not a choice I want to make over and over, and prone to introducing mistakes. +And instead of saying "it might be interesting to add two ways +to reference items in an array", I'm no longer going with that. +Seems like `.Item()` vs `.HumanItem()` is a bad idea. +Not a choice I want to make over and over, +but worse - prone to introducing mistakes. + (Thank goodness for iterators and `foreach ($x in $array) {}` which takes care of the most common "go through all the items" case). -[Richard Feynman](https://www.youtube.com/watch?v=ga_7j72CVlc) was taught to separate -things from how people talk about them, "names are not knowledge", -but too much of that and you won't be able to communicate with people. +--- -Which might be why "there are only two kinds of languages: the ones people complain about and the ones nobody uses" - Bjarne Stroustrup. +On a related note, [Prof. Richard Feynman](https://www.youtube.com/watch?v=ga_7j72CVlc) +was taught to separate things from how people talk about them, +and in this video he tells a story about how "names are not knowledge", +but he also warns that going to far down that line of thinking leaves +you unable to communicate with people, because you don't know what anything is called. -And why there are many LISP dialects and few Java dialects. +Having two ways to index into an array would only make it harder to say which item was "number 1". Put up with someone else's way of seeing the world (along with everyone else), or make up your own (which nobody else uses). -The common suggestion "if you don't like it, change it" rings false. -If excluding someone from a group is rude, telling someone to exclude themselves also is. -Being unable to change something hurts, but being able to change anything -risks people isolating from each other, fragmentation, and loss of coherent direction. - From 321912a2d5fab9d6bd0f74e1a07929a75b452c5d Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Sat, 1 Dec 2018 06:41:34 +0000 Subject: [PATCH 13/48] Update 2018-11-29-Arrays-index-zero-or-one.md Add comment about `,$array | Add-Member` usage --- _posts/2018-11-29-Arrays-index-zero-or-one.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_posts/2018-11-29-Arrays-index-zero-or-one.md b/_posts/2018-11-29-Arrays-index-zero-or-one.md index 927f9396a2085..0d4e7862316e7 100644 --- a/_posts/2018-11-29-Arrays-index-zero-or-one.md +++ b/_posts/2018-11-29-Arrays-index-zero-or-one.md @@ -36,6 +36,9 @@ add a HumanItem() method to an array, and pretend it starts at 1: PS C:\> $array = @('A', 'B', 'C', 'D') PS C:\> $array.Item(0) A + + # Here I use a comma to send $array down the pipeline + # instead of unrolling it and sending the contents instead PS C:\> ,$array | Add-Member -Name HumanItem -MemberType ScriptMethod -Value { >> param([ValidateScript({$_ -gt 0})][int[]]$Index) >> foreach ($i in $index) From f588aa117f7d223e7dbb72b394139f2f59d53309 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 20:49:58 +0000 Subject: [PATCH 14/48] Create 2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md --- ...erShell-pipeline-vs-script-vs-wildcards.md | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 _posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md new file mode 100644 index 0000000000000..7b7802cd201d2 --- /dev/null +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -0,0 +1,148 @@ +--- +layout: post +title: PowerShell pipeline vs script vs wildcards +date: 2018-12-06 +tags: [PowerShell,pipeline] +--- + +PowerShell lives in the middle of two worlds: +writing code into scripts and running it, +and being an interactive shell to run programs and pipe output from one to another. +It was designed to scale, one language which can be written in long-form to be clear and maintainable and re-usable, +or in short-form to be quick to type (aka "elastic syntax"). + +e.g. assigning a variable can be done by any of the following: + +``` +PS C:\> $lines = get-content -Path 'words.txt' +PS C:\> $lines = gc words.txt +or +PS C:\> get-content -path 'words.txt' | set-variable -name 'lines' +PS C:\> gc words.txt | sv lines + +``` + +The usual discussion is about which is clearer and more readable (named parameters make intent clear to other people), +more stable (aliases like `sv` could change on different systems), or more performant (starting a pipeline takes time). +But, working in the shell, I often start typing before deciding what to do. +Typing some code and thinking about what will happen helps me decide, +then mid way through a line of code, I realise it needs to be different. +From that position, all the debates about clarity and maintainability don't matter very much for one-line of code. +How easy is it to change the code I have, into the code I want? +Being able to chain variable assignment on the end is more fluid and less interrupting +than having to stop and edit the front of the line to add `$var =`. + +Another common thing to decide mid-way through typing is that I need to extract some value, +e.g. get the length of all files in a folder, and only the length, e.g.: + +``` +PS C:\> Get-ChildItem | where-object { $_.Length -gt 0 } | Select-Object -ExpandProperty Length +PS C:\> gci -file | select -exp length +``` + +This is almost as short as it can go and switching styles to try `(gci).length` is usually better, +but in this case it returns the length of the array of files, instead of the length property of the members. + +But then I learned about a way to use `ForEach-Object -MemberName` to lookup a property or call a method. +And it quietly suppresses errors so referencing the length of a directory won't fill the screen with errors. +And `foreach-object` has the default alias `%` + +``` +PS C:\> gci -file | foreach-object -membername Length` +PS C:\> gci |% length +``` + +But now we're in the syntax where `length` is an argument to foreach-object, +and it accepts wildcards to find the property: + +``` +PS C:\> gci | foreach-object -membername len* +``` + +The only catch is that the wildcard needs to resolve to one single property or method name, +otherwise you get a screenful of this: + +``` +PS C:\> gci | foreach -member l* +% : Input name "l*" is ambiguous. It can be resolved to multiple matched members. Possible matches include: LinkType +Length LastAccessTime LastAccessTimeUtc LastWriteTime LastWriteTimeUtc. +``` + +Which is intimidating, but helpful - it tells exactly how the match is going wrong. +Part of the fun of using `|foreach -member ___` is playing around to find a wildcard +pattern which is short enough. You can even play for fun wildcards instead, e.g. +`gci | % LastW*Time` is clearly going to end up as `LastWriteTime`, but what is +`gci | % F*L*A*M*E` going to be? Or `$hash = @{'a'=1;'b'=2}; $hash |% g*u*m*r*a*t*` ? + +I play some CodeGolf, the game of writing code as short as possible, +which also makes the code unreadable. It's no use in the real world, +as per the famous quote "*I have made this longer than usual because I have not had time to make it shorter.*", +writing really really short code takes forever. +But the techniques for short code can help, it's much nicer if you can proof a concept or test an idea +in a few short commands, rather than half a page of code. +It makes it more likely that you *will* explore an idea or test something, +because you can progress quickly, +try five approaches before someone else has finished trying one. + +So the exploration of short commands and wildcards for parameters, +trying them and seeing where they are allowed, led me to `get-variable`, +this is the code/cmdlet way of doing: + +``` +PS C:\> $x +PS C:\> get-variable -name 'x' -valueonly +``` + +I have very little idea who uses this as the main approach to variables, +but it also exists as the alias `gv` and it accepts wildcards for the name. +Now: + +``` +PS C:\> $someVeryLongNameHere = 1,2,3,4,5 +PS C:\> $someVeryLongNameHere = 1,2,3,4,5 +1 +2 +3 +4 +5 +PS C:\> $someVeryLongNameHere | measure-object -sum | select-object -expandproperty sum +15 +PS C:\> gv some* -valueonly +1 +2 +3 +4 +5 +PS C:\> gv some* -valueonly | measure -sum +measure : Input object "System.Object[]" is not numeric. +At line:1 char:14 +``` + +*recordscratch* + +And this is the story all about how I tripped over the fact that two ways to get the value of a variable +don't behave the same. `$x` lists the values of a container (e.g. an array) into the pipeline, one at a time. +Get-Variable outputs the array as a single whole item down the pipeline. + +I commented about this on the PowerShell Slack channel, +and Joel ([Vexx32](https://github.com/vexx32) guessed immediately what is happening, +jumped into the source code of the `Get-Variable` cmdlet and confirmed it. +There is a way for cmdlets to write their output to the pipeline, +and they have a choice of whether to trigger enumeration/unrolling of the content or not. + +And because he's a good egg, he fixed it and submitted a 5-character fix to the PowerShell project, +in [issue 8407](https://github.com/PowerShell/PowerShell/pull/8407). + +Whether it will get "fixed" is now a matter of backwards compatibility. +Anyone using it the way it works now, risks having their scripts break. +Since there is already a split between PowerShell 5 and 6, +the team is willing to have some code change, but not everything. +They try to judge if the break is minor, or if the long term benefit is worth it. + +We'll see. + +Still. Try to use both styles of "classic code" and "cmdlets and pipelines" because +more tools means you can do more things and solve more problems. +And write short code in the shell, then each step in a problem takes less effort, +so the whole problem does, so it's solved sooner. +It doesn't matter too much if it's unreadable - most of your command history won't be read. From 5e869eab411de76ce7e4c1f7fc1c12a14169da14 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 21:45:58 +0000 Subject: [PATCH 15/48] Update 2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md Rewriting and tidying up. --- ...erShell-pipeline-vs-script-vs-wildcards.md | 121 +++++++++++------- 1 file changed, 75 insertions(+), 46 deletions(-) diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md index 7b7802cd201d2..655288c0911e4 100644 --- a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -5,13 +5,11 @@ date: 2018-12-06 tags: [PowerShell,pipeline] --- -PowerShell lives in the middle of two worlds: -writing code into scripts and running it, -and being an interactive shell to run programs and pipe output from one to another. -It was designed to scale, one language which can be written in long-form to be clear and maintainable and re-usable, -or in short-form to be quick to type (aka "elastic syntax"). +PowerShell lives in two worlds: scripts, and interactive shell. Scripts tend to look like other programming languages with loops and functions and error handling, they want to be clear and maintainable. +Shell commands look like other shells, with commands and parameters and pipelines, they want to be something you could reasonably type and compose together without too much "programming" overhead. +PS has the idea of "elastic syntax", that one language can be written short-form or long-form, in a programming style or a shell style. (Downside: it has a *ton* of syntax). -e.g. assigning a variable can be done by any of the following: +e.g. assigning a variable can be done by these: ``` PS C:\> $lines = get-content -Path 'words.txt' @@ -22,78 +20,105 @@ PS C:\> gc words.txt | sv lines ``` -The usual discussion is about which is clearer and more readable (named parameters make intent clear to other people), -more stable (aliases like `sv` could change on different systems), or more performant (starting a pipeline takes time). -But, working in the shell, I often start typing before deciding what to do. -Typing some code and thinking about what will happen helps me decide, -then mid way through a line of code, I realise it needs to be different. -From that position, all the debates about clarity and maintainability don't matter very much for one-line of code. +The usual discussion is clarity and maintenance (full names and parameters make intent clear), +or stability (aliases like `sv` could change on different systems), +and in the shell people talk about how much they have to type. + +But in the shell I start typing before fully deciding what to do, +writing code helps me decide what to do, +then mid-way through a line of code, +I realise it needs to be different. +At this point, typing is not my concern, but disruption is. How easy is it to change the code I have, into the code I want? -Being able to chain variable assignment on the end is more fluid and less interrupting -than having to stop and edit the front of the line to add `$var =`. +Part of this is about tooling such as [PSReadLine](https://github.com/lzybkr/PSReadLine) +which handles keyboard shortcuts for jumping the cursor around by word, by line, etc. +But another part of it is being able to rework one style of code into another, +chaining variable assignment on the end with `|sv tmp` is more fluid and less interrupting +than having to stop and edit the front of the line to add `$tmp =`. + +--- Another common thing to decide mid-way through typing is that I need to extract some value, -e.g. get the length of all files in a folder, and only the length, e.g.: +e.g. get the length of all files in a folder: ``` PS C:\> Get-ChildItem | where-object { $_.Length -gt 0 } | Select-Object -ExpandProperty Length PS C:\> gci -file | select -exp length +PS C:\> (gci).length # this one switches styles. But it doesn't work for .Length. ``` -This is almost as short as it can go and switching styles to try `(gci).length` is usually better, -but in this case it returns the length of the array of files, instead of the length property of the members. +The second is almost as short as it can go; switching styles to try `(gci).length` is usually better, +but in this case it returns the length of the array, instead of the `.Length` property of the members. -But then I learned about a way to use `ForEach-Object -MemberName` to lookup a property or call a method. +But then I learned about a way to use `ForEach-Object -MemberName Length` to lookup a property or call a method. And it quietly suppresses errors so referencing the length of a directory won't fill the screen with errors. -And `foreach-object` has the default alias `%` +And `foreach-object` has the default alias `%`, so it became a staple shell pattern for me, overnight: ``` PS C:\> gci -file | foreach-object -membername Length` PS C:\> gci |% length ``` -But now we're in the syntax where `length` is an argument to foreach-object, -and it accepts wildcards to find the property: +Here, `length` is an argument to foreach-object, +and that cmdlet accepts wildcards to find the property: ``` PS C:\> gci | foreach-object -membername len* ``` -The only catch is that the wildcard needs to resolve to one single property or method name, +Which is bizarre because the wildcard must to resolve to one single property or method name, otherwise you get a screenful of this: ``` PS C:\> gci | foreach -member l* % : Input name "l*" is ambiguous. It can be resolved to multiple matched members. Possible matches include: LinkType Length LastAccessTime LastAccessTimeUtc LastWriteTime LastWriteTimeUtc. +% : Input name "l*" is ambiguous. It can be resolved to multiple matched members. Possible matches include: LinkType +Length LastAccessTime LastAccessTimeUtc LastWriteTime LastWriteTimeUtc. +[..] ``` -Which is intimidating, but helpful - it tells exactly how the match is going wrong. -Part of the fun of using `|foreach -member ___` is playing around to find a wildcard -pattern which is short enough. You can even play for fun wildcards instead, e.g. +Which is intimidating, but helpful - it tells you exactly how the match is going wrong. +(Why it supports a wildcard here, when it cannot return multiple matches, I don't know). +Part of the fun of using `|foreach -member ___` is because of the feedback loop of this error message, +playing around to find a wildcard pattern which is short but only matches one name. +You can play for fun wildcards instead of short ones, e.g. `gci | % LastW*Time` is clearly going to end up as `LastWriteTime`, but what is -`gci | % F*L*A*M*E` going to be? Or `$hash = @{'a'=1;'b'=2}; $hash |% g*u*m*r*a*t*` ? +`gci | % F*L*A*M*E` going to be? Or `$hash = @{'a'=1;'b'=2}; $hash |% g*u*m*r*a*t*` +or `gci -file | group extension |% ????`? + +(Another neat one is `gc file.txt | sort *` to sort strings by length). I play some CodeGolf, the game of writing code as short as possible, -which also makes the code unreadable. It's no use in the real world, -as per the famous quote "*I have made this longer than usual because I have not had time to make it shorter.*", -writing really really short code takes forever. -But the techniques for short code can help, it's much nicer if you can proof a concept or test an idea +which happens to make the code unreadable (that's not the point of it). +It's no use in the real world, like the famous quote +"*I have made this longer than usual because I have not had time to make it shorter.*", +writing really really short code takes ages. +But the techniques used for short code are useful in the real world, +it's much nicer if you can make a proof of concept or test an idea in a few short commands, rather than half a page of code. +If you can use programming syntax and command-syntax and mix them up, +you can save deleting and rewriting code differently. It makes it more likely that you *will* explore an idea or test something, -because you can progress quickly, -try five approaches before someone else has finished trying one. +because you can make progress quickly with low effort, +try three things in the time it would have taken you to try one. -So the exploration of short commands and wildcards for parameters, -trying them and seeing where they are allowed, led me to `get-variable`, -this is the code/cmdlet way of doing: +---- + +So explorating short commands and wildcards, +trying them and seeing where they are allowed, +is how I came to be up looing at `get-variable`, +which is the code/cmdlet version of just `$x`: ``` +PS C:\> $x = 1 PS C:\> $x +1 PS C:\> get-variable -name 'x' -valueonly +1 ``` -I have very little idea who uses this as the main approach to variables, +I have little idea who uses this as the main approach to variables, but it also exists as the alias `gv` and it accepts wildcards for the name. Now: @@ -131,18 +156,22 @@ There is a way for cmdlets to write their output to the pipeline, and they have a choice of whether to trigger enumeration/unrolling of the content or not. And because he's a good egg, he fixed it and submitted a 5-character fix to the PowerShell project, -in [issue 8407](https://github.com/PowerShell/PowerShell/pull/8407). +in [issue 8407](https://github.com/PowerShell/PowerShell/pull/8407). This change: + +``` +- WriteObject(matchingVariable.Value); ++ WriteObject(matchingVariable.Value, enumerateCollection: true); +``` -Whether it will get "fixed" is now a matter of backwards compatibility. -Anyone using it the way it works now, risks having their scripts break. -Since there is already a split between PowerShell 5 and 6, -the team is willing to have some code change, but not everything. -They try to judge if the break is minor, or if the long term benefit is worth it. +Whether it will be accepted is now a matter of backwards compatibility. +Anyone using it the way it works now risks having their scripts break. +But there is already a compatibility break between PowerShell 5 and 6, +the team is willing to have some behaviours change, but not everything. We'll see. -Still. Try to use both styles of "classic code" and "cmdlets and pipelines" because -more tools means you can do more things and solve more problems. -And write short code in the shell, then each step in a problem takes less effort, -so the whole problem does, so it's solved sooner. +Still. Use both styles of "classic code" and "cmdlets and pipelines" because +better grasp of PS means you can tackle more problems, with less work. +And write short code in the shell, so each step in a problem takes less effort, +so the whole problem is easier, you can explore more approaches. It doesn't matter too much if it's unreadable - most of your command history won't be read. From 554e8650fc16264f55ca7304fd0455a41abb8a95 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 21:50:27 +0000 Subject: [PATCH 16/48] Update 2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md --- _posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md index 655288c0911e4..26822dea89058 100644 --- a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -5,6 +5,8 @@ date: 2018-12-06 tags: [PowerShell,pipeline] --- +Some background and context for how [Joel's PowerShell issue 8407](https://github.com/PowerShell/PowerShell/pull/8407) was found and fixed. + PowerShell lives in two worlds: scripts, and interactive shell. Scripts tend to look like other programming languages with loops and functions and error handling, they want to be clear and maintainable. Shell commands look like other shells, with commands and parameters and pipelines, they want to be something you could reasonably type and compose together without too much "programming" overhead. PS has the idea of "elastic syntax", that one language can be written short-form or long-form, in a programming style or a shell style. (Downside: it has a *ton* of syntax). From e3c65d99474d1934bc86dcd25b6c841eb65c3bdb Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 22:24:27 +0000 Subject: [PATCH 17/48] fix typos 'explorating' and 'looing' --- .../2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md index 26822dea89058..086d40c1df3df 100644 --- a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -107,9 +107,9 @@ try three things in the time it would have taken you to try one. ---- -So explorating short commands and wildcards, +So exploring short commands and wildcards, trying them and seeing where they are allowed, -is how I came to be up looing at `get-variable`, +is how I came to be up looking at `get-variable`, which is the code/cmdlet version of just `$x`: ``` From 8386153007c313840f0b98fce5e516c909b5499b Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 22:25:51 +0000 Subject: [PATCH 18/48] fix "to resolve to" typo --- _posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md index 086d40c1df3df..032f1c80a9355 100644 --- a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -68,7 +68,7 @@ and that cmdlet accepts wildcards to find the property: PS C:\> gci | foreach-object -membername len* ``` -Which is bizarre because the wildcard must to resolve to one single property or method name, +Which is bizarre because the wildcard must resolve to one single property or method name, otherwise you get a screenful of this: ``` From 6a5f93aeb97ede9864257f3d82c733fca74dc503 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 22:27:53 +0000 Subject: [PATCH 19/48] Pinch vexx32's highlights file for code styles (With his permission) --- _sass/_highlights.scss | 63 ++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/_sass/_highlights.scss b/_sass/_highlights.scss index 57c7b72f07617..b645613b0618a 100644 --- a/_sass/_highlights.scss +++ b/_sass/_highlights.scss @@ -1,31 +1,66 @@ -.highlight { - background-color: #efefef; +pre { + color: #ddd; + background-color: #101010; padding: 7px 7px 7px 10px; - border: 1px solid #ddd; - -moz-box-shadow: 3px 3px rgba(0,0,0,0.1); - -webkit-box-shadow: 3px 3px rgba(0,0,0,0.1); - box-shadow: 3px 3px rgba(0,0,0,0.1); + border: 2px solid #0063B1; + border-top-width: 12px; + -moz-box-shadow: 4px 4px 1px rgba(0,0,0,0.25); + -webkit-box-shadow: 4px 4px 1px rgba(0,0,0,0.25); + box-shadow: 4px 4px 1px rgba(0,0,0,0.25); margin: 20px 0 20px 0; - overflow: scroll; + overflow: auto; + + &::-webkit-scrollbar { + background-color: #101010; + width: 0.6em; + height: 0.6em; + } + + &::-webkit-scrollbar-thumb { + background-color: transparent; + border-radius: 1em; + } + + &:hover::-webkit-scrollbar-thumb { + border: 2px solid #002040; + background-color: #0063B1; + } + + &.highlight { + color: #ddd; + background-color: #202040; + + &::-webkit-scrollbar { + background-color: #202040; + } + } } code { - font-family:'Bitstream Vera Sans Mono','Courier', monospace; + font-family: Consolas, Monaco, monospace; + font-size: 0.8em; +} + +// Inline code only +code.highlighter-rouge { + color: firebrick; + font-weight: bold; + display: inline-block; } .highlight .c { color: #586E75 } /* Comment */ .highlight .err { color: #93A1A1 } /* Error */ .highlight .g { color: #93A1A1 } /* Generic */ -.highlight .k { color: #859900 } /* Keyword */ +.highlight .k { color: #5e5 } /* Keyword */ .highlight .l { color: #93A1A1 } /* Literal */ -.highlight .n { color: #93A1A1 } /* Name */ -.highlight .o { color: #859900 } /* Operator */ +.highlight .n { color: #ddd } /* Name */ +.highlight .o { color: #dddddd } /* Operator */ .highlight .x { color: #CB4B16 } /* Other */ .highlight .p { color: #93A1A1 } /* Punctuation */ .highlight .cm { color: #586E75 } /* Comment.Multiline */ .highlight .cp { color: #859900 } /* Comment.Preproc */ -.highlight .c1 { color: #586E75 } /* Comment.Single */ +.highlight .c1 { color: #689E55 } /* Comment.Single */ .highlight .cs { color: #859900 } /* Comment.Special */ .highlight .gd { color: #2AA198 } /* Generic.Deleted */ .highlight .ge { color: #93A1A1; font-style: italic } /* Generic.Emph */ @@ -59,7 +94,7 @@ code { .highlight .nx { color: #555 } /* Name.Other */ .highlight .py { color: #93A1A1 } /* Name.Property */ .highlight .nt { color: #268BD2 } /* Name.Tag */ -.highlight .nv { color: #268BD2 } /* Name.Variable */ +.highlight .nv { color: #26CBDF } /* Name.Variable */ .highlight .ow { color: #859900 } /* Operator.Word */ .highlight .w { color: #93A1A1 } /* Text.Whitespace */ .highlight .mf { color: #2AA198 } /* Literal.Number.Float */ @@ -81,4 +116,4 @@ code { .highlight .vc { color: #268BD2 } /* Name.Variable.Class */ .highlight .vg { color: #268BD2 } /* Name.Variable.Global */ .highlight .vi { color: #268BD2 } /* Name.Variable.Instance */ -.highlight .il { color: #2AA198 } /* Literal.Number.Integer.Long */ \ No newline at end of file +.highlight .il { color: #2AA198 } /* Literal.Number.Integer.Long */ From 0fe62e3810e98309b9a7b8d7deb8f7b4f3afff86 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 6 Dec 2018 22:52:42 +0000 Subject: [PATCH 20/48] add typo paren, fix 5-char change --- ...2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md index 032f1c80a9355..ddd9858b396e3 100644 --- a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -152,12 +152,12 @@ don't behave the same. `$x` lists the values of a container (e.g. an array) into Get-Variable outputs the array as a single whole item down the pipeline. I commented about this on the PowerShell Slack channel, -and Joel ([Vexx32](https://github.com/vexx32) guessed immediately what is happening, -jumped into the source code of the `Get-Variable` cmdlet and confirmed it. +and Joel ([Vexx32](https://github.com/vexx32)) immediately guessed what's happening, +jumped into the source code of the `Get-Variable` cmdlet, and confirmed it. There is a way for cmdlets to write their output to the pipeline, and they have a choice of whether to trigger enumeration/unrolling of the content or not. -And because he's a good egg, he fixed it and submitted a 5-character fix to the PowerShell project, +And because he's a good egg, he fixed it and submitted a single-change fix to the PowerShell project, in [issue 8407](https://github.com/PowerShell/PowerShell/pull/8407). This change: ``` From 0d05721d505d9c3f411068f6f542a361718c45df Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 7 Dec 2018 01:31:55 +0000 Subject: [PATCH 21/48] add ```powershell for syntax highlighting --- ...PowerShell-pipeline-vs-script-vs-wildcards.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md index ddd9858b396e3..fb1860f3fb1b8 100644 --- a/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md +++ b/_posts/2018-12-06-PowerShell-pipeline-vs-script-vs-wildcards.md @@ -13,7 +13,7 @@ PS has the idea of "elastic syntax", that one language can be written short-form e.g. assigning a variable can be done by these: -``` +```powershell PS C:\> $lines = get-content -Path 'words.txt' PS C:\> $lines = gc words.txt or @@ -43,7 +43,7 @@ than having to stop and edit the front of the line to add `$tmp =`. Another common thing to decide mid-way through typing is that I need to extract some value, e.g. get the length of all files in a folder: -``` +```powershell PS C:\> Get-ChildItem | where-object { $_.Length -gt 0 } | Select-Object -ExpandProperty Length PS C:\> gci -file | select -exp length PS C:\> (gci).length # this one switches styles. But it doesn't work for .Length. @@ -56,7 +56,7 @@ But then I learned about a way to use `ForEach-Object -MemberName Length` to loo And it quietly suppresses errors so referencing the length of a directory won't fill the screen with errors. And `foreach-object` has the default alias `%`, so it became a staple shell pattern for me, overnight: -``` +```powershell PS C:\> gci -file | foreach-object -membername Length` PS C:\> gci |% length ``` @@ -64,14 +64,14 @@ PS C:\> gci |% length Here, `length` is an argument to foreach-object, and that cmdlet accepts wildcards to find the property: -``` +```powershell PS C:\> gci | foreach-object -membername len* ``` Which is bizarre because the wildcard must resolve to one single property or method name, otherwise you get a screenful of this: -``` +```powershell PS C:\> gci | foreach -member l* % : Input name "l*" is ambiguous. It can be resolved to multiple matched members. Possible matches include: LinkType Length LastAccessTime LastAccessTimeUtc LastWriteTime LastWriteTimeUtc. @@ -112,7 +112,7 @@ trying them and seeing where they are allowed, is how I came to be up looking at `get-variable`, which is the code/cmdlet version of just `$x`: -``` +```powershell PS C:\> $x = 1 PS C:\> $x 1 @@ -124,7 +124,7 @@ I have little idea who uses this as the main approach to variables, but it also exists as the alias `gv` and it accepts wildcards for the name. Now: -``` +```powershell PS C:\> $someVeryLongNameHere = 1,2,3,4,5 PS C:\> $someVeryLongNameHere = 1,2,3,4,5 1 @@ -160,7 +160,7 @@ and they have a choice of whether to trigger enumeration/unrolling of the conten And because he's a good egg, he fixed it and submitted a single-change fix to the PowerShell project, in [issue 8407](https://github.com/PowerShell/PowerShell/pull/8407). This change: -``` +```powershell - WriteObject(matchingVariable.Value); + WriteObject(matchingVariable.Value, enumerateCollection: true); ``` From 77d1509404c93dc69a6edbf520a9b1aee94fee19 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 7 Dec 2018 01:33:20 +0000 Subject: [PATCH 22/48] add ```powershell for highlighting --- ...12-01-Reading-N-characters-from-the-end.md | 52 +++++++++++-------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/_posts/2018-12-01-Reading-N-characters-from-the-end.md b/_posts/2018-12-01-Reading-N-characters-from-the-end.md index b39ea0f3198a4..9fe9d5fa4ad55 100644 --- a/_posts/2018-12-01-Reading-N-characters-from-the-end.md +++ b/_posts/2018-12-01-Reading-N-characters-from-the-end.md @@ -20,24 +20,28 @@ That's easy enough, I thought. (TL, DR. It wasn't). #### You can use .Net to read the last 20 bytes from a file easy enough: - $numBytes = 20 - $file = Get-Item -Path .\bigfile.txt - - # Open file as a stream, - # and seek back from the end. - $stream = [System.IO.File]::OpenRead($file.FullName) - [void]$stream.Seek(-$numBytes, [System.IO.SeekOrigin]::End) - - # Read some bytes from it into a buffer, - # and decode them into text - $buffer = [byte[]]::new($numBytes) - [void]$stream.Read($buffer, 0, $numBytes) - $stream.Close() - +```powershell +$numBytes = 20 +$file = Get-Item -Path .\bigfile.txt + +# Open file as a stream, +# and seek back from the end. +$stream = [System.IO.File]::OpenRead($file.FullName) +[void]$stream.Seek(-$numBytes, [System.IO.SeekOrigin]::End) + +# Read some bytes from it into a buffer, +# and decode them into text +$buffer = [byte[]]::new($numBytes) +[void]$stream.Read($buffer, 0, $numBytes) +$stream.Close() +``` + *And* you can turn them into a string, easy enough: - [System.Text.Encoding]::ASCII.GetString($buffer) - +```powershell +[System.Text.Encoding]::ASCII.GetString($buffer) +``` + Which is alllmost fine. Oh btw, what's that over there... --- @@ -119,17 +123,21 @@ then decoded back to text another way. Let's see a couple: Smartquotes like `“` run through UTF8 then back through UTF16-LE: - PS C:\> $bytes = [system.text.encoding]::UTF8.GetBytes('“') +```powershell +PS C:\> $bytes = [system.text.encoding]::UTF8.GetBytes('“') - PS C:\> [system.text.encoding]::Unicode.GetString($bytes) - 胢� +PS C:\> [system.text.encoding]::Unicode.GetString($bytes) +胢� +``` Text through Unicode then back through UTF8: - PS C:\> $bytes = [system.text.encoding]::Unicode.GetBytes('test') +```powershell +PS C:\> $bytes = [system.text.encoding]::Unicode.GetBytes('test') - PS C:\> [system.text.encoding]::UTF8.GetString($bytes) - t e s t +PS C:\> [system.text.encoding]::UTF8.GetString($bytes) +t e s t +``` There's a few common versions of these, and a few more when considering HTML like `£` showing up wrong, From a25c859d195a96aebfd410805b65ce9f13e17199 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 7 Dec 2018 01:34:29 +0000 Subject: [PATCH 23/48] add ```powershell for highlighting --- _posts/2018-11-29-Arrays-index-zero-or-one.md | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/_posts/2018-11-29-Arrays-index-zero-or-one.md b/_posts/2018-11-29-Arrays-index-zero-or-one.md index 0d4e7862316e7..dd6494af80855 100644 --- a/_posts/2018-11-29-Arrays-index-zero-or-one.md +++ b/_posts/2018-11-29-Arrays-index-zero-or-one.md @@ -24,43 +24,49 @@ See it as a *choice*, and then ask if we talk about two valid ways to access it, why not *make* two ways to access it? The language need not choose, programmers can choose: - $array = @('A', 'B', 'C', 'D') - $array.Item(0) # -> 'A' - $array.HumanItem(1) # -> 'A' +```powershell +$array = @('A', 'B', 'C', 'D') +$array.Item(0) # -> 'A' +$array.HumanItem(1) # -> 'A' +``` Then you can walk it with either sequence over the items: `0 to N-1` or `1 to N`. PowerShell arrays start at 0, but we can fix it, add a HumanItem() method to an array, and pretend it starts at 1: - PS C:\> $array = @('A', 'B', 'C', 'D') - PS C:\> $array.Item(0) - A - - # Here I use a comma to send $array down the pipeline - # instead of unrolling it and sending the contents instead - PS C:\> ,$array | Add-Member -Name HumanItem -MemberType ScriptMethod -Value { - >> param([ValidateScript({$_ -gt 0})][int[]]$Index) - >> foreach ($i in $index) - >> { - >> $this[($i - 1)] - >> } - >> } - PS C:\> $array.HumanItem(1) - A +```powershell +PS C:\> $array = @('A', 'B', 'C', 'D') +PS C:\> $array.Item(0) +A + +# Here I use a comma to send $array down the pipeline +# instead of unrolling it and sending the contents instead +PS C:\> ,$array | Add-Member -Name HumanItem -MemberType ScriptMethod -Value { +>> param([ValidateScript({$_ -gt 0})][int[]]$Index) +>> foreach ($i in $index) +>> { +>> $this[($i - 1)] +>> } +>> } +PS C:\> $array.HumanItem(1) +A +``` Then write: - PS C:\> $array[0..($array.Length - 1)] - A - B - C - D - PS C:\> $array.HumanItem(1..$array.Length) - A - B - C - D +```powershell +PS C:\> $array[0..($array.Length - 1)] +A +B +C +D +PS C:\> $array.HumanItem(1..$array.Length) +A +B +C +D +``` PowerShell arrays start from index 0, and it has an array notation `0..4` to make a sequence of numbers, From 443900a4a3e6b008b0a5454b706971fa82e9ee17 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Sat, 8 Dec 2018 10:41:43 +0000 Subject: [PATCH 24/48] Create 2018-12-08-Speed-Tweaks-AoC-Day-8.md --- _posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md | 370 ++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 _posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md diff --git a/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md b/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md new file mode 100644 index 0000000000000..63d802c6b057b --- /dev/null +++ b/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md @@ -0,0 +1,370 @@ +--- +layout: post +title: Speed tweaking Advent of Code Day 8 +date: 2018-12-08 +tags: [PowerShell,performance] +--- + +The [Advent of Code Day 8](https://adventofcode.com/2018/day/8) puzzle starts with a single line of integers, +and asks you to parse a tree out of it. +[My code is here](https://github.com/HumanEquivalentUnit/AdventOfCode2018/blob/master/2018-12-08-PowerShell-p1-and-p2.ps1), +and [my input data is here](https://github.com/HumanEquivalentUnit/AdventOfCode2018/blob/master/2018-12-08-data.txt); +this blog post is about how I tweaked it from 1.1 seconds runtime to 0.205 seconds runtime. + + + +The testing code is `measure-command { .\code.ps1 | out-default }` and that shows both the code result, +and the timing data. It's not very accurate - use System.Diagnostics.StopWatch for that - +but run it two or three times after a change, and it's good enough to show gain or loss. + +At this point, I had written it with a stack, a `switch` and some lists and it was working, +running both parts in ~1.1 seconds. + +After spending a while tweaking, I got it down to ~205ms. + +Then I hit `Ctrl-Z` a lot in PowerShell ISE to undo the changes, +and documented them below. This is a reverse log of trial-and-error 80% speedup. + +---- +### Next +What drives the state machine? I had `strings` for states, like so: + +```powershell +$parserState = 'NewNode' + +switch($parserState) { + 'NewNode' { + } + 'MetaDataCleanup' { + } +} +``` + +and I thought `enums` might do a number comparison and be much faster than a string comparison: + +```powershell +enum state { + NewNode + MetaDataCleanup +} + +$parserState = [state]::NewNode + +switch($parserState) { + ([state]::NewNode) { + } + ([state]::MetaDataCleanup) { + } +} +``` + +Result: much worse! Much much worse. +Removing the strings and enums, and going to integers with simple `$stateNEWNODE = 0` +for states was significantly faster, ~100ms, I think. + +---- +### Next +When parsing a new node, make a hashtable and setup lists to hold the childNodes and MetaData values: + +```powershell + @{ + ... + childNodes = [List[psobject]]::new() + metaData = [List[psobject]]::new() + ... + } +``` + +I wanted to make that conditional, to save the cost of initialization, so I tried something like this: + +```powershell + $childNodeList = if ($numChildNodes -gt 0) { [List[psobject]]::new() } else { $null } + $metaDataList = if ($numMetaDataEntries -gt 0) { [List[psobject]]::new() } else { $null } +``` + +Result: SCREEN FULL OF EXCEPTIONS + +Scratching my head long time, tried several variations, until I realised the `if` was enumerating +the values from the empty list, and assigning `$null`. I would have to `,` in front of it to get the +list back: + +```powershell + $childNodeList = if ($numChildNodes -gt 0) { ,[List[psobject]]::new() } else { $null } + $metaDataList = if ($numMetaDataEntries -gt 0) { ,[List[psobject]]::new() } else { $null } +``` + +Result: no benefit, maybe even slower, and ugly code. Reverted. + +---- +### Next +In part 2 adding up the metadata values: + +```powershell + $currentNode.value = ($currentNode.metaData | measure-object -Sum).Sum +``` + +Tried to cut out the pipeline and cmdlet invocation with this fast loop: + +```powershell + $localSum = 0; foreach ($m in $currentNode.metaData) { $localSum += $m } + $currentNode.value = $local +``` + +Result: bigger speedup than I expected, worth doing even though the code looks uglier. + +---- +### Next +The state machine was "state 0, new node is starting" and "state 1, node ending". Code like: + +```powershell + $parserState = $stateMETADATACLEANUP + if ($nodeSkeleton.numChildNodes -gt 0) + { + $parserstate = $stateNEWNODE + } else + { + $parserState = $stateMETADATACLEANUP + } + + + # [..] in the cleanup state + + + if ($parent.childNodes.Count -lt $parent.numChildNodes) + { + $parserState = $stateNEWNODE + } + else + { + $parserState = $stateMETADATACLEANUP + } +``` + +This use of if/else tests every time through the loop was bothering me. +Eventually I realised that they're not really states, +they're counters for how many child-nodes still need parsing below here. + +```powershell + $parserState = $nodeSkeleton.numChildNodes + + # [..] and this + + $parserState = $parent.childNodes.Count - $parent.numChildNodes + ``` + +Now it falls to "state 0" when there are no childnodes or none remaining, +and "state N" (switch 'default') when there are some. +I might have swapped the switch statement order around as well. + +Result: pleasingly less code, some speed improvement, quite small, not really worth doing. + +---- +### Next +Reading the metadata after all the childNodes are done, +I had a fast loop adding to a Generic List: + +```powershell + # + # previously # 1..$currentNode.numMetadataEntries | ForEach-Object { + # + foreach ($counter in 1..$currentNode.numMetadataEntries) + { + $currentNode.metaData.Add($inputNums[$i++]) + } +``` + +but with a bit of thinking about how `$i` would move during this, +the loop can go, and be replaced with a multi-index lookup and direct array assignment: + +```powershell + $currentNode.metaData = $inputNums[$i..($i+$currentNode.numMetadataEntries-1)] + $i += $currentNode.numMetadataEntries +``` + +and lower down / earlier on at the node initialization, +`metaData = [List[psobject]]::new()` can become `metaData = $null` saving setup time and memory. +Result: pleasingly large gain, can't remember how much, but in the ~30ms region. + +---- +### Next +Realised I was calculating the `$localSum` twice. Once from Part 1 of the puzzle, and again for part 2. +Removed that duplicate work. It helped a little. + +---- +### Next +In part 2 of the puzzle, there is a lookup into the childNodes 1-indexed offsetd, and a sum of their values. + +Earlier it had been a loop with a check: + +```powershell + $m-- # 1-indexed here + $node = $currentNode.childNodes[$m] + if ($node) + { + $currentNode.value += $node.value + } +``` + +and I had removed the `if` because PS will handle reading from an array where nothing is there, +and casting $nulls to int 0. At this point it was already a fast `foreach(){}` loop like so: + +``` + foreach ($m in $currentNode.metaData) + { + $node = $currentNode.childNodes[$m-1] + $currentNode.value += $node.value # might be $null, but PS is fine with that + } +``` + +And made no check for whether the childNode even exists, or the value exists, PS will cast those to $null/0 implicitly. +[It occurs to me now, that implicit casting is a bit slow, it might be faster if I hadn't done this, and used if/else]. + +But I hoped to use a multi-lookup with `childNodes[$currentNode.metaData]` instead of a loop in my code, +make the PS Engine loop in faster C# code behind the scenes. To get around the need to `$m-1` every time, +I shunted the nodes to the side by 1 and used this: + +```powershell + $currentnode.childNodes.Insert(0, 0) + foreach ($v in $currentNode.childNodes[$currentNode.metaData].value) { $currentNode.value += $v } + $currentNode.childNodes.RemoveAt(0) +``` + +Result: measurable, pleasing improvement; from memory in the ~25ms region. + +---- +### Next +The code to start parsing a new childNode makes a hashtable and pushes it on the stack. +Then does a property lookup to reference the number of childnodes to find which state to go to next. +I wanted to avoid that property lookup, so I inlined the state assignment into the hashtable literal. + +```powershell + $nodeSkeleton = @{ + numChildNodes = $inputNums[$i++] + numMetadataEntries = $inputNums[$i++] + childNodes = [List[psobject]]::new() + metaData = $null + value = 0 + } + $stack.Push($nodeSkeleton) + + $numNodesAtThisLevelToParse = $nodeSkeleton.numChildNodes +``` + +turned into: + +```powershell + $stack.Push(@{ + numChildNodes = ($numNodesAtThisLevelToParse = $inputNums[$i++]) + numMetadataEntries = $inputNums[$i++] + childNodes = [List[psobject]]::new() + metaData = $null + value = 0 + }) +``` + +Result: from memory, mild improvement. + +---- +### Next + +Starting with `using system.collections.generic` and then writing `[list[psobject]]`, +I tried changing to `[system.collections.generic.list[psobject]]`. + +Wasn't expecting much and no performance change that I could tell, but by this stage I was only using it twice, +so I left it in. + +---- +### Next + +The original data reading was `Get-Content .\data.txt -raw` and then a line split and cast to int. +I thought it would definitely be faster avoiding the cmdlet and using .Net file reading. +But .Net has a different idea of "the current working directory", and I wanted to handle that. + +```powershell +$lines = Get-Content .\data.txt -raw +$inputNums = [int[]]($lines.Split(" `r`n")) +``` + +Changed to a long and ugly line such as + +```powershell +$inputNums = [int[]][System.IO.File]::ReadAllText((Get-Location).Path + '\data.txt')).Split(" `r`n") +``` +But it was no faster. Just now, I've thought of `$pwd.Path` to avoid that cmdlet call, +but I can't tell any change one way or the other. Change reverted. + +---- +### Next + +The "state machine" had boiled down to two states, +and I swapped this `switch` pattern: + +```powershell +switch ($numRemainingChildNodes) +{ + 0 { + } + + default { + } +} +``` + +for this simpler one: + +```powershell +if ($numRemainingChildNodes -gt 0) +{} +else +{} +``` + +I wasn't really expecting a change, because switch is a builtin, but it helped ~10ms. + +---- +### Next +Once the stack is empty and we're nearing the end, +I need to avoid calling `.Peek()` on it, that's an exception. + +Code started as: + +```powershell + # empty stack means $current is the finished root node and we're done. + if ($stack.count -gt 0) + { + $parent = $stack.Peek() + $parent.childNodes.Add($currentNode) + + $numRemainingChildNodes = $parent.childNodes.Count - $parent.numChildNodes + } +``` + +First try was just to comment out the `if () {}` block and let it throw an exception, +and deal with seeing the error message. That's worse, generating an exception is ~25ms slower. + +I looked around for any other method than reading and comparing the count, +hoping to find `$stack.Empty` but it doesn't exist. +Second try was to add a fake-node to the stack when initializing it. +This helped by ~5ms. + +```powershell +# at the very top, push a buffer node onto the stack. +$stack.Push(@{childNodes=[System.Collections.Generic.List[psobject]]::new()}) + +# now at the end, this will always succeed, no need for a special case + $parent = $stack.Peek() + $parent.childNodes.Add($currentNode) +``` + +---- +### End + +Final runtime, in ISE, with several runs, varies around 205ms. Down to ~197ms and up to ~250ms. + +I didn't keep a log of these at the time, so this is dependent on PowerShell ISE's undo buffer. +Stepping back through my changes, *most* of them were rewriting and shuffling comments around, +rewriting variable names, and laying out code. + +(All of the numbers are imprecise. Numbers like ~5ms and ~25ms are only rough indicators +of effect size, as I percieved it, on my system. Trying to recreate a couple, ISE seems to +run this script slightly faster than PowerShell.exe). From 81bb689d24e40997228c4f98d84b7c59bb03630c Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Sat, 8 Dec 2018 21:49:29 +0000 Subject: [PATCH 25/48] Edits and tweaks after a second reading. --- _posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md | 136 +++++++++++++------- 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md b/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md index 63d802c6b057b..aa9795a778459 100644 --- a/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md +++ b/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md @@ -11,6 +11,8 @@ and asks you to parse a tree out of it. and [my input data is here](https://github.com/HumanEquivalentUnit/AdventOfCode2018/blob/master/2018-12-08-data.txt); this blog post is about how I tweaked it from 1.1 seconds runtime to 0.205 seconds runtime. +Click for a [1 min 40 second video of my undo/redo buffer from the start to the end of all of this](https://github.com/HumanEquivalentUnit/AdventOfCode2018/blob/master/2018-12-08-PowerShell-coding.mp4). + The testing code is `measure-command { .\code.ps1 | out-default }` and that shows both the code result, @@ -18,7 +20,7 @@ and the timing data. It's not very accurate - use System.Diagnostics.StopWatch f but run it two or three times after a change, and it's good enough to show gain or loss. At this point, I had written it with a stack, a `switch` and some lists and it was working, -running both parts in ~1.1 seconds. +running over an input of ~17,000 numbers, getting results for both puzzle parts in ~1.1 seconds. After spending a while tweaking, I got it down to ~205ms. @@ -27,7 +29,12 @@ and documented them below. This is a reverse log of trial-and-error 80% speedup. ---- ### Next -What drives the state machine? I had `strings` for states, like so: +The core of my code was a while loop until the string ended, +and a `switch()` based state machine which was going to have states like "starting a new node", +"starting a child node", "getting metadata", "updating the tree", "returning up a level". +It ended up only needing "start of a node" and "end of a node". + +So what handles the states in the state machine? I had `strings` for states, like so: ```powershell $parserState = 'NewNode' @@ -40,7 +47,9 @@ switch($parserState) { } ``` -and I thought `enums` might do a number comparison and be much faster than a string comparison: +and I thought that string comparisons might have to be done from start to end, +and PS does them case insensitively so there might be a lot of work happening behind the scenes. +`enums` have integer values, and a number comparison might be much faster than a string comparison: ```powershell enum state { @@ -58,13 +67,15 @@ switch($parserState) { } ``` -Result: much worse! Much much worse. -Removing the strings and enums, and going to integers with simple `$stateNEWNODE = 0` -for states was significantly faster, ~100ms, I think. +Result: worse! much worse. +Removing the strings and enums, and going to integers with my own code, +using a simple `$stateNEWNODE = 0; $stateMETADATACLEANUP = 1` +for states was significantly faster than strings or enums, ~100-200ms, I think. ---- ### Next -When parsing a new node, make a hashtable and setup lists to hold the childNodes and MetaData values: +When parsing a new node I make a hashtable for it, +with lists to hold the childNodes and MetaData values: ```powershell @{ @@ -84,26 +95,29 @@ I wanted to make that conditional, to save the cost of initialization, so I trie Result: SCREEN FULL OF EXCEPTIONS -Scratching my head long time, tried several variations, until I realised the `if` was enumerating -the values from the empty list, and assigning `$null`. I would have to `,` in front of it to get the -list back: +Scratching my head long time, tried several variations, +until I realised the `if` was enumerating the values from the empty list, +and assigning `$null`. I would have to use the trick of putting `,` +in front of it to make a 1-item-array wrapper so the unrolling works on that and leaves the list alone: ```powershell $childNodeList = if ($numChildNodes -gt 0) { ,[List[psobject]]::new() } else { $null } $metaDataList = if ($numMetaDataEntries -gt 0) { ,[List[psobject]]::new() } else { $null } ``` -Result: no benefit, maybe even slower, and ugly code. Reverted. +Result: no benefit, maybe slower, and ugly code. Not sure if memory use improved, but code change reverted. ---- ### Next -In part 2 adding up the metadata values: +In part 2 adding up the metadata values (sum a collection of ints): ```powershell $currentNode.value = ($currentNode.metaData | measure-object -Sum).Sum ``` -Tried to cut out the pipeline and cmdlet invocation with this fast loop: +I wanted to avoid the pipeline setup cost, +and cmdlet name resolution and initialization costs, +with this fast loop: ```powershell $localSum = 0; foreach ($m in $currentNode.metaData) { $localSum += $m } @@ -111,10 +125,13 @@ Tried to cut out the pipeline and cmdlet invocation with this fast loop: ``` Result: bigger speedup than I expected, worth doing even though the code looks uglier. +Could certainly be spread onto more lines, +but makes me wish for Python's `sum(Iterable)` construct. ---- ### Next -The state machine was "state 0, new node is starting" and "state 1, node ending". Code like: +The state machine was down to two states: "state 0, new node is starting" +and "state 1, node ending". Code like this: ```powershell $parserState = $stateMETADATACLEANUP @@ -142,7 +159,8 @@ The state machine was "state 0, new node is starting" and "state 1, node ending" This use of if/else tests every time through the loop was bothering me. Eventually I realised that they're not really states, -they're counters for how many child-nodes still need parsing below here. +they're counters for how many child-nodes still need parsing below, +before we can get to this level's metadata. All that became this: ```powershell $parserState = $nodeSkeleton.numChildNodes @@ -152,9 +170,9 @@ they're counters for how many child-nodes still need parsing below here. $parserState = $parent.childNodes.Count - $parent.numChildNodes ``` -Now it falls to "state 0" when there are no childnodes or none remaining, -and "state N" (switch 'default') when there are some. -I might have swapped the switch statement order around as well. +Now it falls to "state 0" when there are no childnodes at all, or no more remaining, +and "state N" (switch 'default') when there are some new nodes to start. +(I think I swapped the switch blocks around as well at this point). Result: pleasingly less code, some speed improvement, quite small, not really worth doing. @@ -181,18 +199,19 @@ the loop can go, and be replaced with a multi-index lookup and direct array assi $i += $currentNode.numMetadataEntries ``` -and lower down / earlier on at the node initialization, +and lower down in the code / earlier on in the exeuction when setting up a new node, `metaData = [List[psobject]]::new()` can become `metaData = $null` saving setup time and memory. -Result: pleasingly large gain, can't remember how much, but in the ~30ms region. +Result: pleasingly large gain, can't remember how much, but ~30ms region ish. ---- ### Next -Realised I was calculating the `$localSum` twice. Once from Part 1 of the puzzle, and again for part 2. +Realised I was calculating the `$localSum` sum-of-metadata-for-a-node twice. Once from Part 1 of the puzzle, again for part 2. Removed that duplicate work. It helped a little. ---- ### Next -In part 2 of the puzzle, there is a lookup into the childNodes 1-indexed offsetd, and a sum of their values. +In part 2 of the puzzle, there is a lookup into the childNodes 1-indexed, +and a sum of those values. Earlier it had been a loop with a check: @@ -205,8 +224,8 @@ Earlier it had been a loop with a check: } ``` -and I had removed the `if` because PS will handle reading from an array where nothing is there, -and casting $nulls to int 0. At this point it was already a fast `foreach(){}` loop like so: +and I had removed the `if` because PS will handle reading outside the bounds of an array, +and casts $nulls to int 0. At this point it was already a fast `foreach(){}` loop like so: ``` foreach ($m in $currentNode.metaData) @@ -216,8 +235,8 @@ and casting $nulls to int 0. At this point it was already a fast `foreach(){}` l } ``` -And made no check for whether the childNode even exists, or the value exists, PS will cast those to $null/0 implicitly. -[It occurs to me now, that implicit casting is a bit slow, it might be faster if I hadn't done this, and used if/else]. +(It occurs to me now, that implicit casting is a bit slow, +it might be faster if I hadn't done this, and used if/else). But I hoped to use a multi-lookup with `childNodes[$currentNode.metaData]` instead of a loop in my code, make the PS Engine loop in faster C# code behind the scenes. To get around the need to `$m-1` every time, @@ -267,11 +286,17 @@ Result: from memory, mild improvement. ---- ### Next -Starting with `using system.collections.generic` and then writing `[list[psobject]]`, -I tried changing to `[system.collections.generic.list[psobject]]`. +When I started I had `[system.collections.generic.List[psobject]]` all over the place, +and was annoyed with typing it. [Joel Bennet / Jaykul](https://twitter.com/Jaykul) in the PowerShell Slack chatroom +reminded me that `using system.collections.generic` can go at the top, +and then each one can be shortened to `[list[psobject]]`. +At this point in my code I had cut down the use of it quite a bit, +and wondered if this namespace lookup shortname-to-fullname might cause a measurable delay. +It does in a lot of PowerShell, resolving `where` to `where-object` takes time, for example. + +I tried changing them to `[system.collections.generic.list[psobject]]`. -Wasn't expecting much and no performance change that I could tell, but by this stage I was only using it twice, -so I left it in. +No performance change that I could tell, but I left it in. ---- ### Next @@ -290,14 +315,17 @@ Changed to a long and ugly line such as ```powershell $inputNums = [int[]][System.IO.File]::ReadAllText((Get-Location).Path + '\data.txt')).Split(" `r`n") ``` -But it was no faster. Just now, I've thought of `$pwd.Path` to avoid that cmdlet call, -but I can't tell any change one way or the other. Change reverted. +But it was no faster. Not much surprise as I left another cmdlet call in there. +While writing this, I've found `$pwd.Path` to get the PS path and avoid that cmdlet, +but I can't tell if it makes any change one way or the other. +Change reverted because it's too ugly this way. ---- ### Next -The "state machine" had boiled down to two states, -and I swapped this `switch` pattern: +Here's when I realised the "state machine" had boiled down to two states, +which could be simplified to an `if/else`. +I swapped this `switch` pattern: ```powershell switch ($numRemainingChildNodes) @@ -310,7 +338,7 @@ switch ($numRemainingChildNodes) } ``` -for this simpler one: +for this: ```powershell if ($numRemainingChildNodes -gt 0) @@ -319,13 +347,13 @@ else {} ``` -I wasn't really expecting a change, because switch is a builtin, but it helped ~10ms. +I wasn't really expecting a performance change because switch is a builtin keyword, +just wanted it shorter and cleaner. Surprisingly, it did help ~10-15ms. ---- ### Next Once the stack is empty and we're nearing the end, -I need to avoid calling `.Peek()` on it, that's an exception. - +I need to avoid calling `.Peek()` on it, because that throws an exception. Code started as: ```powershell @@ -339,13 +367,20 @@ Code started as: } ``` +But this means doing the `if` test for every node end, +when there's only the root node which will empty the stack. +How wasteful. First try was just to comment out the `if () {}` block and let it throw an exception, -and deal with seeing the error message. That's worse, generating an exception is ~25ms slower. +and deal with seeing the error message. +Would saving the test cost many times win over the large cost of raising and propagating an exception? +No it wouldn't, letting it throw an exception makes it ~20-35ms slower. -I looked around for any other method than reading and comparing the count, -hoping to find `$stack.Empty` but it doesn't exist. -Second try was to add a fake-node to the stack when initializing it. -This helped by ~5ms. +I looked around for another way to do the test than reading and comparing the count, +hoping to find `$stack.IsEmpty` but nothing looked good. + +Second try was to add a fake-node to the stack when initializing it, +now I can .peek() the stack and it will never be empty. +Avoids the test on every node and the exception. ```powershell # at the very top, push a buffer node onto the stack. @@ -355,6 +390,21 @@ $stack.Push(@{childNodes=[System.Collections.Generic.List[psobject]]::new()}) $parent = $stack.Peek() $parent.childNodes.Add($currentNode) ``` +This helped by ~5ms. + +---- +### Next + +Somewhere in here I learned that implicit casting is slower. +For a long time I have advocated `if ($x.Thing -eq $true)` -> `if ($x.Thing)` +and in a similar way `if ($x.Count -gt 0)` -> `if ($x.Count)`. +PS can and will do the implicit conversion to `[bool]` so let's use it. + +But the operator `-gt 0` seems to be faster than `[bool]$x.Count`. +There are reasonably complex rules for what PS objects are truthy vs. falsey, +so perhaps there is overhead in going through those states, +and "number -gt 0" can ultimately boil down to a single CPU instruction. +(Not sure if it actually does, but it could). ---- ### End From 41017d0f19317fbde4eb665bfb3c78c06a369115 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Sat, 8 Dec 2018 21:56:14 +0000 Subject: [PATCH 26/48] change video link to streamable.com --- _posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md b/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md index aa9795a778459..6c24717a3ead8 100644 --- a/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md +++ b/_posts/2018-12-08-Speed-Tweaks-AoC-Day-8.md @@ -11,7 +11,7 @@ and asks you to parse a tree out of it. and [my input data is here](https://github.com/HumanEquivalentUnit/AdventOfCode2018/blob/master/2018-12-08-data.txt); this blog post is about how I tweaked it from 1.1 seconds runtime to 0.205 seconds runtime. -Click for a [1 min 40 second video of my undo/redo buffer from the start to the end of all of this](https://github.com/HumanEquivalentUnit/AdventOfCode2018/blob/master/2018-12-08-PowerShell-coding.mp4). +Click for a [1 min 40 second video of my undo/redo buffer from the start to the end of all of this](https://streamable.com/8lnzs). From b9b0dfd82a7c9cf8b16d443ea021d08379be16a0 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Tue, 18 Dec 2018 09:24:18 +0000 Subject: [PATCH 27/48] Create 2018-12-18-AoC-Day-1.md --- _posts/2018-12-18-AoC-Day-1.md | 64 ++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 _posts/2018-12-18-AoC-Day-1.md diff --git a/_posts/2018-12-18-AoC-Day-1.md b/_posts/2018-12-18-AoC-Day-1.md new file mode 100644 index 0000000000000..52636d6f88379 --- /dev/null +++ b/_posts/2018-12-18-AoC-Day-1.md @@ -0,0 +1,64 @@ +--- +layout: post +title: Advent Of Code 2018 - Optimizing Day 1 +date: 2018-12-18 +tags: [PowerShell,Optimization] +--- + +Taking Day 1 code from 3.1 seconds to ~63ms. + +As I left it, the code to Part 2 read an array of integers from a file, +repeatedly adding them up until it found one it had seen before. +It already used a dictionary for a fast lookup, +and `.foreach{}` for a fast loop, it took over 3 seconds and looked like this: + +```powershell +$nums = [int[]](get-content .\data.txt) +$lookup=@{} +$current=0 +while ($true) { + $nums.foreach{ $current += $_; if ($lookup.ContainsKey($current)) {break}; $lookup[$current]++; } +} +$current +``` + +(I ditched the commandlets and called `[System.Io.File]::ReadAllLines()` and `[Linq.Enumerable]::Sum()` for Part 1, ~30ms saving). + +Changing `$nums.foreach{}` to `foreach ($n in $nums)` means the `break` needs adjusting with +[a label on the outer while loop](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_break?view=powershell-6). +This loop change makes it twice as fast, down to around 1.5s. + +Switching the hashtable for a `[Collections.Generic.Dictionary[int,int]]` helps a lot; +generic collections don't have overhead of boxing/unboxing integers. +That brought it down to ~67-70ms, +but `[System.Collections.Generic.HashSet[int]]` looked interesting. + +Instead of doing a two-stage Dictionary Add/ContainsKey, +HashSet.Add() returns True for a first time addition, +False if the data was already present, +so it's now a single step store-and-test-if-previously-seen. +That saves 5-10ms. + +Outputting two values to the pipeline, surprisingly costly. +5-10ms saved by using `[System.Console]::WriteLine`, +presumably avoiding the output formatters. + +This is how it looks now, both parts running in 2% of the time of the earlier code: + +```powershell +$nums = [int[]][system.io.file]::ReadAllLines('d:\aoc\2018\1\data.txt') + +# Part 1 +[System.Console]::WriteLine([System.Linq.Enumerable]::Sum($nums)) + +# Part 2 - keep summing until a repeat is seen. +$lookup = [System.Collections.Generic.HashSet[int]]::new() +$runningTotal = 0 +:outerLoop while ($true) { + foreach ($n in $nums) { $runningTotal += $n; if (-not $lookup.Add($runningTotal)) { break outerLoop } } +} +[System.Console]::WriteLine($runningTotal) +``` + +(My measuring code is `measure-command{ .\Day1.ps1 | Out-Default}` which is not the most precise, +but good enough to show cutting 90% of the runtime off). From 826a5671f4f64293c9bf1e0ecffd8a84469c1939 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Tue, 18 Dec 2018 09:24:42 +0000 Subject: [PATCH 28/48] Rename 2018-12-18-AoC-Day-1.md to 2018-12-18-AoC-Optimizing-Day-1.md --- ...2018-12-18-AoC-Day-1.md => 2018-12-18-AoC-Optimizing-Day-1.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename _posts/{2018-12-18-AoC-Day-1.md => 2018-12-18-AoC-Optimizing-Day-1.md} (100%) diff --git a/_posts/2018-12-18-AoC-Day-1.md b/_posts/2018-12-18-AoC-Optimizing-Day-1.md similarity index 100% rename from _posts/2018-12-18-AoC-Day-1.md rename to _posts/2018-12-18-AoC-Optimizing-Day-1.md From f7b462e5e535aa54d1dec0811e78053eb0aeae27 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 10 Jan 2019 23:28:38 +0000 Subject: [PATCH 29/48] Create 2019-01-10-apcrancid-in-2019 --- _posts/2019-01-10-apcrancid-in-2019 | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 _posts/2019-01-10-apcrancid-in-2019 diff --git a/_posts/2019-01-10-apcrancid-in-2019 b/_posts/2019-01-10-apcrancid-in-2019 new file mode 100644 index 0000000000000..7a850865003d2 --- /dev/null +++ b/_posts/2019-01-10-apcrancid-in-2019 @@ -0,0 +1,43 @@ +--- +layout: post +title: Using rancid-apc (apcrancid) module in RANCID 3.8 +date: 2019-01-10 +tags: [networking,Other] +--- + +The tool [RANCID from Shrubbery Networks, inc.](http://www.shrubbery.net/rancid/) +will login to network switches and get their current configuration, +'diff' it against previous configuration, email you with any changes, +and save the configuration to a version control system (cvs, svn or git). + +Modules can add support for different manufacturers, +HP, Arista, Juniper, and many kinds of devices - +if it has an SSH, telnet, or ftp interface and can list its configuration to text, +it's probably workable. + +APC UPS management cards have network interfaces for monitoring, +and APC environment monitoring units have as well, +and there is a third party module [rancid-apc.tar.gz](ftp://ftp.shrubbery.net/pub/rancid/contrib/) +in their unsupported contrib folder. + +It was built for RANCID v 2.x and the newer RANCID 3.x range works differently. + +To get it working, I: + + - extracted the .tgz + - edited the `apcrancid` file and changed `#! /usr/bin/perl5` to `#! /usr/bin/perl` + (find out where perl is with `which perl` or `locate perl`) + - edited the `apclogin` file and changed `#! /usr/local/bin/expect --` to `#! /usr/bin/expect --` + - copied both `apclogin` and `apcrancid` to `/usr/local/rancid/bin/` and make sure they are `chmod +x` + - the `rancid.fe` file has totally changed in v3.x, so don't copy it over or try to apply the patch. + + Instead edit `/usr/local/rancid/etc/rancid.types.conf` wherever you installed it, and add: + + ``` +apc;script;apcrancid +apc;login;apclogin +``` + +Then add these devices like any other to your `routers.db` file, with the type `apc`. + +That seems to be enough for this to work with 3.8. From 0a4aa0b1c1638503c2aeb6fa3a2ba0c6b8a0f7c5 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 11 Jan 2019 01:35:00 +0000 Subject: [PATCH 30/48] add .md to filename --- ...19-01-10-apcrancid-in-2019 => 2019-01-10-apcrancid-in-2019.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename _posts/{2019-01-10-apcrancid-in-2019 => 2019-01-10-apcrancid-in-2019.md} (100%) diff --git a/_posts/2019-01-10-apcrancid-in-2019 b/_posts/2019-01-10-apcrancid-in-2019.md similarity index 100% rename from _posts/2019-01-10-apcrancid-in-2019 rename to _posts/2019-01-10-apcrancid-in-2019.md From 828d0fa064d9cf00952c95f3897e182526a3604f Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 05:43:56 +0000 Subject: [PATCH 31/48] Add files via upload --- images/image.png | Bin 0 -> 21575 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/image.png diff --git a/images/image.png b/images/image.png new file mode 100644 index 0000000000000000000000000000000000000000..2ded78e598dd999c33db59019adcaa8d035c2cc7 GIT binary patch literal 21575 zcmdRWRaBcn*KR3NyoDk`i#wFy4#nNwAwY30P}~Cq2?V#|&=%L?6emb=cXudW{N(%3 zcdpLWxjZ*nvu3?BYu=sNdq4Ymb`q_wDu;tfiuvl*D;x!RY0X!!kR%Y}0(3OQC#M5J z+N)PouN0&|X@AW=Zof^Vn8|1y?YxSMo4zYL)s>WH6ajEkLQi~ZGQ4d>wt}Y_BTsed z0LuMV7}#h@T_}llDDslh3QS)F^4(9q28e6NSa2TkvSR_iRXSAo{g|`A{tflL z=W`=gx=n`kL$g@1fxvS}Pc&E?F~0wqOltm9`$uZICbDu0%M47%J{U1=SgVM`sq<4? zN%sd*iDHU9oQ3x{;&FC^VzhJ?ouBk&)33A;`&gy?UyI{{C26VF{=(;;-ajsGFpBSy zGTt{p^~9RNX>DsZ{|Mu0XY{V`UgpMv{BnaTH*&}Q?BHbPm6Qop53zib{i@Z}+lNTa zh7y$|Feg+iGNk4fwT?jdRik{8Kv}#9U1^I+#<>gl^vjKNuy)W1Z;d(Sb%HVb{m{T= z#DEDDt}SeJNO`9V^;gMGm@~OR6IjHC^S zw;i~j?g00kJxQFNuS*gtd7Vp@IQP1Ga@}BA!|23O+8mIj^f0-d)61 zh!r+aHtY7f9+io|{80S{`#x4Ueq~TYZ8cNUnL{wR2oLr%d;3m9n(?CPqUJrfpCB&s zmBB<5i4z$67p~j$4g{+bo4EMQjO5~}%rCnc4yvZ)6!Nj8soH8``ia-s)W=8wl=Fpr zc;d4unqe@Si&gOk{0O&V5VkV9B(R5dm8jWF(yqA=@_;aT)BI=Xf8`GhfqV3MZAPu2 zjwV3ew|8CF6rsPXPdwr3tW;~R%sir8Nw{~0zirtWgh@D;qnM^?bY~?oJ#%Ypq%Ei= zhj~F<4N=R}A`4*4a=~GFl?1!~*x7)7d&&i0>HG~?l|p}}i7u~{uIeb)BEfbH(n6ex zSJ3`tSM2Um+6QY}sa{(dE?rOf3^G?k@VRd~03=E^Cm(P2-ETV!sTne?kGKy+)dke> zY1)ehzJ(IC{27q-6zE!8x@3df)Eho00yYBDs^l8afa>wMm-jW&uSm-7tTIhx8E9om zfvktrpp^7;U*-H6>N$7#6Ar`v%Rt!yuq8p*@8Bt+@qLXK3!T{|d=^=j`1GvGKRYgX z*=hu0DbdK=^H+P&o3GJlE1|y^*lk-hZhSpR9yXfp*f6}G>}Nb6$bme^z zUpK7ZXI)Opy-Hwpgi9O8vBe(g$etH?%XTJ+_tGqC{(aTjTI=uF9Ev`3vv-qIN(Z;lr^2J9%9`gg|GgTqNW)&A`N5e>Bm4*Ed2$c?i)R1%B9c$`jh1vNr02-v|7+X zo`BklU}aj%a=f~N!|H;?VonlnO)MrJ8d(NQC6_~O{crN7HUu#S`CC-Afk%;Ust@xzNf1o{X#HHVhQtp{jUK|dPzQ-zpJ#G{y z5MFacwDia;QO-$uoTKSO^(Wq8|7x)!17=ae9D^*}S}sxH6l21Vhkp`AlBvubf~*!}>}vrwD9*(4TC_I{V4b zMa%{>$;N&`Zz|Zx0zVoEiprG`T=bBkC=M)Nrc#^X3Y6`*@Amu18X;xC6E?tOUukKy zh_^HG3P(9UtBkq-L5ocBgc|eGOvRF9$HH}dv-t#j=8G(K1b2_&K7STD$Mg$(TzMJh zAaK=|#~yl78}i|Y56piS+|zZgqm)(L{`5l)ruGwD?zat1bY}y&;?if5C^{O7M@h(p zVtJ5jdMoPU3b6yKB$P2ocUbNK$0Eq?~wYzjC~@1XQLg~P?4ac zB}U7ermU5i6AR}R$`)PO$Yzc__k}tRGm57We8X%A=4FpGW;Jg+biXOt4uQ!An}rh5 z{FY?hY=EMuQoRh2t`EVibZB>z!RC%1$nFG~d9Z z)G-4+V}{M8xP(?p)TbU#Got3+Ds*^9C^c?!8)FFsOo^x+&x+jUTb+P8eziHLU(zHe z)>Cv{M)DFno}L#v@Mep7$F5Kr)i8Ft-t=fja#o2Srq@9BRD$p4kDK;YBVn_PI!YVf>e$k7!+oT%P z(rH~AXgEzhhV2%6qssaBJ;ZNJ|HPIeW0^)o2fABvD0{;D%v~vj7e>f6gz2< z@O>5f-)m%ie$5vU&fjAdv9}%6&AN8m0MKqKs$-1 zkNU-Z{wsFWkAVP>l^B=@|Cgq}ivW7I$X1Tl&%AFt2rs&y)76=5mZQ#IN|f?B1Yhi- zg%qP*-!@KjaJ}2NFD7EGII_3aoWBez_dO0b;Dt<+iwTS^)rCf`!rC6=m6&*2-#YwB zKfNe)pg9d>?~k!;NgQ+fi1mCuo1im;dq$x_enInRWsz1Z#_q8r>^%zkm4Dz1WIZtl zX@$vrEp{Wcg0fjwe&^I+S8}+67MA7J^k|XReaZVE1YB$B-7Cnl`D&Ziy^s6gmnv+Q z`nbNBFp;@^5oscV=bBfz@Ep1w-A;Wnztz*6{=sCiFlcCF?pL@iAt(3Q#jf#)l;7^% z#tvTdBAl7v$z|47l*TB=K$Ot+zJ6dR4mM>7{OpLm;6v5_7S!RBVKq}UmWdOpGlf*D z#w^S58UD+++)@6*^QWkw|liT>ipV%`X&Z>^+lJizYlRTiNVJ z>h&ovM3TNusjS1s!C+`2q*4Y6<=afnTKxO8Lmm!g_qct6D0 z96m?+kM4A(p?q2{X)#I2Ai&o354>rOQvL2@msYHvyJhBbj&3!wQJDI{#4W+GZ|C^H z;M*cGJ}WfFS>1|-a?e?$S9zfNAgDZrboz34>7hv9Gn#P)%``|MYGG=>?Bd_hqrs@^;;R#EMSY zNc@FeW>0aU0`=f;^&hVzza|uKE+5uswJBfTD3Jqg&euN4jGBW|V_Yyb7&b>~#ezCz zs#}N>*lz~azGai01=ZDFN9kNc7tTAZU$T21JSZPNi>^8th0fDY13!$tInKopO;-i1C$xLd*(V`{-Y`Dv$yvA)};c`nR22GP@;DN-zX0JEC0r<{k}_d4h`GmtwObE=B-%|6T8^!ZAReMfpxb zg{<*&0^KZla)p{!C$gqxdteS#zryEVMR5K-TLzq?a1?5{{82;kqP5gSS4Hsnth?*m z=G-sO=D%Rv7q@`4T$7+=sgrbMCk1D%-U$AG;hKMYRpH~wY9*^Bos_OSQ%JJEdnv@E zMiZufU8Nt`-;nE+|9r4A0)l2JA8=W5g@8ew^xKho{a?A(cc3lh-}|ljZUE)C`n(73 z6TFdvFSU2u4EEqyHOif(v_F?CYvIOUK+rd)aq3)o_YdihV1qxc{c`)1&@(Uiua;OI zg3gxaFis@3(>M}lR4cTTSuWFM^KyX-JCaJ1a zYrRt!5zb~R3Psw-F1ljPU5w73%dKuLlmNa>iWjGCJ2?jP!pMF$Y-53W{~juUVGU9K zQ~By?jMn9#nW$x}NV&CSTjp`TUeX91U?Q(bE#vm_0pHzEhPkUj9kmf;_j5dRQ7aiK z1ninvyD(U|B5`So9^=V#HD5LvUPYa%HB5a`CLwvl#8vua53L(M&pzfz%5pF zs@LYrxm`$$Z@u2U0yAc{Y$JW#L3a(4E7@>8pvBcBBfa&BRr6#{4tO5(q?W}z^%J&f z!mnw09RbV#q8F0q4YPP z)7h=fQ|C8+{z~lRZ{MlLGPu@M)H7i^a!O0>a99`H=&#Ekuqx^(xUSgIUOXzp--}Lo z`OkS&-9XFsi@ph7ET73e8Q7Sj|B&P5OG6KqAMeUH8tqgs0(_?EY0CGvfZCm4EDjAO z>#xV`JzqsFn=0*=$@1#A<4aqy=Wt4S{jBUEb^MsPUw9*5!|lidI67veY=`629=6FK zjukz26;bc6!_6jtGHR@6Dx^&vQn)uH%*=3Y zs3uIv^3q?xhU=>S39}t78txI6`oae6FNl4`nh2m=ExYU2&N7~&7Z+4(WMHmWRfcQ} zl>DXyjUoW+$lq z?hevjT$Ts^p+$1@eOd4v=OmMS`j+1L61Tf#B(&T?D-jcQpTn{6Blv>};kpu3ZY>Vr zL}AgiaT#MIS~M;4Xee!_l<4vWt`h0LH(5AxLvThuQ@(&-`#g&)sb9HDJvd9iYDj%2 zn=Bj5C;{S4Gv>DZjt6rRurj2)11mYRtnY*YYZwKbgy{6H;rs|-kucFhwd4vY8z4Bu zTbNA)3STnwh+Ob?$%}55+dTMIcgT2}#w6`_p^i+YU+&)vAc)mrSK=Rj6a1#m+VyqYf)Bs>>Hq*=*15 z(NF3(KIhBj)9Y(^85np1$^;&rBP9TRJJ6A&jC#kQKh%6kGkzldq@nq~gCCu7qh+$7 zLe)Q4LAH}y{I_7+DbRg>LW)k`g^E+4zjbhZ>Vua7g6v3aK~!*-mVW4x9w*#j#~$l} zCA^jK9pYco*t|GFbMA;sIcPGbRO!oSRZrx)aVA+X?mFP0Fg7)$J19T8HyMdsRGWPI z1yIKFXK``od)a)Dbix{bO#ux_*3G;}uj^o)zk|o%5RTK$7DX8V)~wyu;u(rn<2_0f9bB5?1VUC+H+jin0!fGKez5ei6;1 zAjQEqc1E6RcS*&+OI3O0S@b@AhRx&fa z^rkyw)S$lvnQP`WjVpd@5DC0Zs_-(OX*k0DfRZ!Lp|~P3FJX-l z_9MK|aN85jR^fv2g!0wnnp;pvG~tqI&d!=Me!1g)8~1zn@#wqRdbtujPM=)4?>v#a zpvr)L(9$JG-APoK2d;SYpS^m8NIfxhSIeH0G3LhQxviRZFf<;MCja{~HA%&Xovbue z@>5b{wYsN>;GiZhtESZ*2qV1(wx5`L^Swf(pBb*JNuQr6{B6(?mpWm2Cp*<7F26`p zITs1LB7)h8Ff>FFoEYLomUR$gwMVK7r25;#=fE$$O)A#In=5&V_`2xk2x4{o124a( z>C4&D{szQCqT@E+`n~@1^A_Nu4|b?CTkNM8SU_io*Y6&<-230wM!C3L6BVC1UjMsE z4J*$%bx23hJ-#{=L;NwhUk$P^+HvGDuKj1p_5xygc8r*Pr>)@8xWfbcV zqJWZYADw|J-cZI19!ehz9&-kGBj7X&;&^}x??Hal&&s29Cxm@(X>k;e7gL@H+J%C`?&LHFOLeT<&i#E{P0wBaKB#7^JB!@m?G#Dz!NA6s z;$}?AIY74d&a|tQJ9O6xcOjL=?7Hc=E2=#b<)IavyG9Aif&i-ejlDX@PJ6^W;&;sX z*CXE2aI{#aD$~-LdEbq#p|4s^VuGzPq$@&ORI+4Qr(ZFq7Kv3;LnboRj!a_x*){uq}JVZTr%(;lJ-%M?JV%2*rK^4;XjB;$nQ9h~Uc59C` zr#<-Z)#5soSk^WK*Dy!c*hESy{jDfbswC916)68MU{ykcnIt-^+GrrSP^f+cb7Gb) zyNq={7w`uChWJW1F6`FpLZ|q>2kU9v<2VWtv_D&aCNTp8MTO&4UBlTln5i}kVr&nkrgVMDb3lB{{ z%O$pIM0U-DMPL1}{)&OEQw$Lwni$5s3Wm9m5`+Pvin8 z(s<@`Jw3^DE;p)b3WDG7lpIZP&1&M#4&6u{knaN(F$^~NU+9e5iqe^h3+7P&k9=@Q$4aLMO``vSlUDQ7 zstv)u3&v`j)Uu};Uv3xm{cqtxK_?%NbCw{M9~FU({HJKAT;bC+m{?}iiNXqNdP)D6 z&hY;rQg|xn2vsD-p7}8OgYikye`o(qCj56~ zj`QC&nEL;HjsQfB*zZSbfhsjUJ-u}_jMQ9FaR`Rs?UR#}>6Pq*nVFfDQV}N7)J$bV z*r2G0%>eP93JM0bMQG_TSgn-;4kuzE{Qtj&J4!$ahgZnv)$-UtsxJF#z6lJWcwpXy zEgcaCxiDI^=CdL;QN*W$1lzLee!9JReRanDI%$xGEgfbAQ0UGz4z)cmIr;ra8Yo!T zGOpJiUwjgNUG^$kmP&2VEjA?>6knU!t;k4bs6n>h%zKUf!Qi~s~Qw20=EWXI6M$@c<(HuN2!}UG#YcHyawQ)4xlN-sG#N}vL-6oI1s(mOHx*$Ck=ZgiHrmuJhb|$=x-Sh zLM4jp$2UMPrjf4zA;1aqVaTXNii z2A`^$kF$W%zSJ7F^3FvOS9za6;&4KH9%`2WM|=w7Y_A~fR$N;z%H-pF{lBwvsU~l5 zT5qJ@9c&Go8Ne>>=;chhvgD54Vp;F9a^4WMilw&sNLWx2{XH(gN0Z~xV# z!Fjrd$kz^kQQK}hc6J%*$xbf}g5-KXy5KOc9eC`#$9sFyK<-W?CPf&gTFHlHz9T6_ zM{n(x{SKKxHY`L{&2f)tpTV;HmDNGo=ws)Hq_*erJ?sgxf2Suj!CKxG8!v&hGOrWqF5;(&HWJ4RzomW z(9*`;Ti!&|^bUitSt1Y*S_~g%@^74t&{Xp#0EZ#+ksmg(l&m6T14GHH8}xma!RU*R zE7aTAfD6RiFHN-(Uy7aK`CKr-E3m;OumRLejwQg!z)&dJ(DhKlosNUu- z<@V9Ubz!0xtyk)??U@~Ls%KjGsEq5ykT7|ZaI_E%Wsda0Muc*?87cTyX}<>PQcqKt z&oJTW#{lg*_^r>g)6vzLZbtkb2WB8zA8!C`1K5=@@ML56V#;QF`5;~!pV1wM9bB_2 zfvXv*`&s6|F9yH=NZ~EYSG!Zcs@GS(IAgT2{Y&WR$FV&k3)PzI!>&leR{a;7>=&CX zOaKwR*ul-Pgm!s`S{JA9c*+E}ug_AzB;?EsBYx5_u_j?;NAF`m>wewrm;J*|4wJDn znE3qtm{a?hQ~xlr;w!eUv2MAZ$Zb3{aic)(2MRVGpzC_f&%a{U;HoJ#%^z)uvZt6M ztdFCI5ZVPp7%F|4h^qME^MH=-JKNz#3ZR4i<&~bl>=1PrJ^Z&c)Ogg|M}b=#hva*` zfoayx^rFb{Q095T0O8x-E1DP?>I#*SwdY&;DN7Aq*ZGjmQQQFfNXG?G6We}n6oAy)wB>^Jh7s_xRqJ1sDyqnowd;!wb-{*uqo(Ke*%H$SpRhL>^=#`)B|;o zP`4hcvibp1MJRJ3$6UrS{|xJTfc}nB$%Q(+gn3 z3hY$|7IZe{b{VFfU*pY*S!2}S(baOv=9i<9Y=x&@mJraspD0LSX03fs*<3p;L2qtA zZ)L!0X`8dIcD6sZ`eKG2r_#^7K3j?-bwn&)nOIB5jhDzO6swJ#s`EOPpKf>vZ^sF; z?@_WV`Fr#u3ihle8Vfi?6KdTTWz4>vW%Qb(4Y)qHBoY`1f?{!CFca`@5kFw3iKY?@ zTg8}g`0#W`^MKz)D^NP-_IFQw+gUr?KlgqQPJ|8A*5-8*)choLe9Q*-(G2T; zb_{5IX<&jee_`J1=Oo2M#}$vqRYGQDDr)uJDc7Ruw9Ziyp&1&O9#^|Ph{VU&=;jsa zf2U)NV>4u>Twymbxh46gj-8AQ9unnfle{QhA!0<2j*vi?VG_mlgBay<`}@s|}|-@|+koz=(0bYLr|1 z2EY;dc&`hc!?j)3f5#e~3`~R_pOHBG|Jl0w5!?|Iwk-EuF$&?Y6=$D-XCh^8w{o02Zw0F&x|vBMR6=Wwfw@D%BE6qWao4 zFA3Mx9i#xl-27`Xsg&Rt7o2kth9Z^0<1_*6u&yDmp&t;T3sKEub~)qHOvTnV=J@9{ zcuEq++l5i)`?3>q4sR;w1r)xMyd392tV@|<0g zl*_xn7aKmJTuaCF*_8?d(%6Z-WIrBv#cvllSfVMK+{cJL72^`GalEUMq4^ZtNG)kl zO)V#sS;u#eokjsx3f=fQ(Bg#Tk>AgB*KG1}$d+=^&Opb7Tm6QFsTn&>igJOOle8X> z@qn)M(Z%u{&Gt8GL=CC6RAms0m2JCP5U+V&xvgUs<20tja>VH@sQ>DKbwA+gd_zwDKZc~ANLxbB}tY9o1^x=3iC z<8Btbo~<*q*g1rsI^8q2lyfw<1>vbv+ZjpGBK=Sn7cYOC>!l{6bo5h2!|Lca2( zAO9IiNAnM*ASs}B_Gh0T182{4?-=^$-#M`lidQwVkX-KjaV%iuYR!3*uwl*eEsfkz z^@johtT3=W&9_zh{g08@+AWA!t?F_uFixaTMitjf+B*L6`p0D@d;Cq)zeZIUE1S<% z3eTu;E0Yq}jH-eGT@1fOYxQIgi@)8!1Dw$Of}$$?>RP(T7~3y64|Ph zOsCjl;Q&-R9aC16M7+mCn^6g%O%nl^F`lCjlcaqZeoUtw8&w4oj5)J9)z8#hzh?EX zw+e###l1aoA2<9|K0a&iN)(X2MGX&Su8+r)z0_F0+`@r$*vJP7T5isg_-aZ4*x9I$ z8GfK4&!-1?Kx)8nwmsi=R2<|UV$<$%}=bdLhO5g_u+{*Iezo{UZZFp`)SEaaIy5m?tt%E z(Mj!--ADKVp{Oi`V%Ehws^K?!%q+fL{*ltG^C6e!1%Szm8IhhJEnoTy$Xi?#R>dXe)3Ddd;1)sR!_98JeBLCc`If>;LG(8;I>at^d| zoCP0gpy68*Hct``+45|N06B_nPWi|<)5soyYCVRl>ezd7+drSnV!$YAsL0>SGV+paCQ5~KgF&)+Qi|5Zxd)0X@zi&^NUHtpA z3$Vs9WO&<=oZRQ?kH*9c$Tg9pHggwf;2JPjs6A~A{w)v`NRiol6~E(Ej#dE*ybT{V zXQtuafU){M9>()&5a4ALA?efpYoaA77qA*alIn|^nWBtbWXUjmE_Ndw*FB$zr89!U z38d~hyZ|})#}D&V$8G>By5Vcj-t5AE0}fK)S%hz(iZ^waQluyG?L4t98WzR9t6Bfa zNDGDlr5X~H1vhI%qq`pOKJ)=FQqx7{ELF<{5n84!1C8!4A%78<-~E6>&Y{xO(srWoD^Mj#9}qD9_e*b)`!_ ztO3c;uv|x??cFF@JsuNEKMSQFV_p>jmv#oor*9`Rts&8{ph5oRqxA&a;wv091^kT@ zLCb%4o*s`^;Dn%dvGsTgYE9YPtSdE|kcjJVviZq*^%Y8HqcG-sY;BrKAGY7NGT#Yi z8Su6{q<}p$Q5)A{83h9iM#j6MmwiGnPWTmn{2+uCQT`L3iwHQ?Z+v!7&^^f$Gy2R^ zB$=cxza<=pk6qLbxHgP(pM^73RGVptDH?^Oq%y9hl>d;uQX9FvuC;ukh>R+h!3$V5 zqi#Tz+zsek$Pz)bhb-SGgur@oZ|IuEL8wERMKypzqWe?jS_h@_g@Adk*;oUyiTo-W zfeMjYn_u_gw*|{*myOQ@G-0dYzG`!``Agx z0EsC?PZh-E9s)kR;piS5i&NIpe8wNZLt3;Frn3Xet}BMT%am90C!vaa$Os)^42o!Y z?S#^AxcYD2-S-GRz*?#VA6DhL;P=~K(;PT!S-zPQ2JC4_-#~P26$}d+kuSyoCEicD zp|X-9Enq?qmVoQv@%s!FCHl35F)#i}a)L~awyyKF!HG;%&@-7v< zUOLO_sT2lRIsc4is{kRy@@Wr{vkd%V(klU^Gm72+=)>~@peh8-tN}odT&SmZU>LX+fAW_lvDF&|0CM+)z`PyY>BgQT-IEfj|86BfC@p*Qo-BF zVB-Y~17^$e{n|TfxbgQSr=QCBeIJH*Wb-$7i4kpxB4B&G;kk$GRza)VSmf8g-_%sQ zKzZ|$M7Bk%zP6W`c&&9{``@5j_q-#Ni=EPGOEO7IeW;D`ilzohaV}8=cr+7ep zh57-}p3pctg-g)yi=L$%RL&(|=;jY6G4iz0@}Cr}kx6+is4*XpajCir#&6rQRAH`+-Vg2X-e5Td_%yV~$cId5wQS@1d^zL1pm3E#_*@l>hkb zv4~aE1~XjT1gK^P- ze@1k0t#uX*+i6jtl~E5n0GllbT^Bw-HKzAa=PA7}Buo+Ic0R|s{7hsFC*q85w2}_6(Vyjzs1)m`MnUkL%+;JwtT9{j zK?c>r@^5LZGGK>9Z<*y6Is`f$^$rr2%b&Dp+Mm#aVW**NAv9+#?sDfpi9fvVd{q)m zss>ehjlV|h_T8dr+LkM%UfLxoTZ?nMNBKYgcHQxyE-Tp`RQ=Bpu88UHYR#?7Ml*jH z=uYpEe7|R7Rl1<>8>%(G6oo+jkaQO#RDSTz7PWR2v3)~OT`9Ht#Xj36UA3N}AwR9Y zGYuwVH@p9qFCLXx*-ArXoNeah=xRPRR@icZ3g6_MVQ}=qjb*R73?~nshke7q5M({$ zmVha`k$O?T8q;pO`#A@#5V<_=>$7N&ty_FP%-Z#dtyEW%>j*ipW>n^=)3{vT>yxT3 zCyHX-K?fyrpN}jHo>^JAv2Uk=ZBHUr+*ihhS1H|#3292s^*M4tnbHolkQ zUuxYXy%{#^)>m@mwaEK=g)_VePsq2I2nvYbNh!omX^l>=6VqIc(bPyAP9BgRdSl2Ag?6>{Tr6tb57%L*NO8$X1-8@k<8f+# z165CNeW*J4J0d6M#wIafOGa0^T!d#nw0WnAtxgt`hzIQ?OfcEwHqNomBRId-{EdKZ z!w_oPBU&_8yw8o~l`Z1i2_OwVH1?WZeYLDl`GO)J-0!v1{8gs(4!QKB|E(5Z9^b!0 z;BCL24696gx_)$;LZ7?fowf>&9?#sa7-TN%+^V$q$d5Z-Z!b}?IS&?)91y}(xxte1 z&%v;r;0E5v0J)@ZQmyJ0+J|(jQT^sA{W>tSRs2aa2!QDtVDQ0pN{eP;P`j+idt(1% z{g2v)P$;zN@q#GwS#wYVUf7AxX`H;x(MT}saL+0hkdm;Il5U+6^$aQM1i+pewg=Lh zMLN``rnoZPS&1MFFDFa@!oMRNksgizu$BL@u`;%zThBUR5*vY)@SakFI~0@2OUZ%y zF$ZSEb@r0#Z9NvZBJu?h6ycL8RLn7Z2*UW&B;WZdUe7hu!Fd6%HX!mp9c~;g9RnmP zksS~a-}LFZU{IY@ zAWcyxd3Bp-REXxtkb5NAHy~4mL~!+L_iY26LwhmN;|<2Ak^&NzUnES82Bwz)gT23R z(@?cfbN5;(kba4M@aW4Gd47_G){$~Z9nsvAQQVWtkrnwe& zxF`-{FKOU2m_-AC&IymR>ZZ@|u83Q=?Wv#Mi=r{MB%fhM(?p9j{(RB;T4TLw1GRn+ z?vjOeT?0!~E$>+=9ZD9BzpC_(xp>}9xbQgqggh6hmCyjneIA!)@VrlANxp|~Gt#8a z`5P{6eVlz`OT`E4@c=hyQ3s@OgcbkiXA%Q`EE&&%GPa=T6!V@HAmScru~IJ7<~_@W zs80|dV%O*v#`dKrkjP#1tbMim>6A*0j5aLV&nVd_;`sH~`}Zu-vtIdJWziKDomhHj z==vt9Y#;Bibwt2Qlv_AZiU$$()Oj?loY(lpC~C)71_oK6rrilWcM=wG_OGt35K(Xj zr}UxKbpo%#_94@-(g)T+H;=*fK3Io6G|^r9TNcrflN+ef6YG-ECT{tqUCB%VX7T~Z zLw#UYMS@7EX~<|0C$4MUo)kV>`bey*OpD6WrrRC9QeD)A==2@yNLI>N@z3@*J}zj< zy2}^Y1LNW51~b-qhkuiXc}-3{LOTdfnyN8x{KP(M)2On03pQ+47Z6-tSj5d-U=`Ew zDx7L&1Rs4;y(mOkV^S{@^!*qSIGT^HIpLlqMQpI7i@yEY{fOmkdal%YLv<4&x4}+hS^!Hk zHlYcaHS;h>v|#Y1uByJCZjBmGCbe`8_V}+Q;k-mD2%cZHJEfQNc_DoGWoESNd0Her;us$bryl6butqcnG%W6@K7F;ij8TWfk*Ee|NAFkfUB6Lzp@ zdi1U$5x+_THTCn%@bRkcK$m7fTg$-4X~HLi!OcI_pL_)RCOAR}OvlWeg#Di@RHz&^ z$)mMM-I<|u3*NKWuMx)i{6l2zTbYU4XF@98$&)?zq0K~35=b{1eHWd#3<|WJa)6X= zU}9ho4V(R~`c`qK)#bo=bH`hjhsR(mTNS=d`@#msa80KAtc@pH+#MCZkZP&E&@yGi zBx;LiMsK!rL<6)4~n~;Cl|eBxa>yUj>7it^v=t1Xq4E@h2BCSpqi&V>Cwj-YhxQ z)4ob%7x<~(jU|-VUVE#k#KjWkMStQ3|3|oj5(=A?51mZtT6*JH&xfbDX&;snmzvGqinhMl|8|bF1pdVXXNlk45VtwxTB*yVNw>$)1w2xuA%9E4>6aXHvc-9#{|ps zjh0c9^buC6mu|+V=8?n*pI*?d5eo7+a+D&cMv;ti1ghr*{8@rnZ~ZOh z;q0>PBd#UGNAJ!oSC;Vw9IQ`XW*OdTCi562hhv}mQGW_j^xG+S7N8F4?N5c=RT(8q zbD?A^L%JDQy^Wai-CSK!M}mYEs0z@-ldxmv%a^}Veu-JVJrC6&RXEa7n9Mvk<>H37>q%3wW|OMx{_EW^#SrNIE+!_N0#CK(g3|3eZCGdX7EqEWKt8 zcNqeLHK_^x1N&*l>6l~YlOvRE+8oUVojX#u-i|30)DnV-0;rg9OPTF>m~a=$=fA;A zEv--yC6=}3C1WS*;up4nOB`QnKz#l3u%jZ8| zE4dbb>IUvN612w`uvWmEzM_)2gLW`0aP@szjgz(g-9BmHDQJ-LGGVr|eXV;t3~$f; zw5!Y6pTRNOo-g1nGnM?Ynxvg+v_|z!@==4=V+6{$7q6P5va8(S?rD^QT~g0aCyelm zN0@2n3K_Jt=)&uyzBxG(HKba_XWrsIlgDmKW<@$r-XUZXw^AErEfE`wB$+2OIh=j= z#J!CwCKa8Ss12l!@6P0;3>2}gv&cPRFLM#ms=A0xt!L!bQBsCTn)cq^jzZ2h0~P#p zjXt9*na8E#E6IQRIz{!)3tbvNSq5b(zBqw@!bU1dB|716A4w7{p{R&i%Eu!U&dOcH zw#3>@&ub{)_$1W#6r&Yu0w}e&6VK`#p$hjw^j|;4e}zxTe|dk*y^eR_lpWfIKhe&nnPFE?o z$<1H*zK@)8eEv0bI)ARH%f9OT9=(_egN#6iH&Nw@e}Uh0*H7?6o4IxCYzB&?LVs1l zl@MRY+wnbJl5YI@%M}BmuA^2|nS35=EMxE+r)O`_$C`R+bh01qgSq$|iVERGO@F(Dxs4MF)$g?$1^fq65$Yh z%zWeUMz?y27)NF_r@Z92TE{=8oF!=vIx4oVNILj&jYzwRZR^sg(j{j4;?efve>UJ(k{$lLo&Dl7%|!C%g4+0 z+Drt@Jv+~Y0Vt9r5aKHhA|l7TGzko3c3w>b^c~+owH=xUy>dy#xMK2phuVi^D`}X@NEv`AspCev%j`eEWyHn5!2DQ+o7xbn}md1D0wQxf0_VP?u5Wc77Ep`<rWgivk6kR?kTN@t>Cv^@NHbg1S$7uD%&Xb;VsRy-QapPK#u0rRR76>vsW0W> zjqziSp2vPGsLf~eSU4k%o*_P)!W^y&62z^%y4NcrhjX8KYLSP-O2kef^Y#Ae{a=#x z7OWF;s5HZ1e3DGca@?0PNfx7MgmKJZenH2@s^_gpt;5gnKjGL?w@<&*JD+PO>f7My ziz6ALL93g^RDKZB`1gTS&v)23r03#<&l^064W&buW@F$u-Z;Xo+DECJ6YkZ0osXh9 z&*Vhg5LS)qgb}%LWc)e~t@u;S%bX>bcTQZPN)cR=0Yh8?U)ZFXJ%nT>*E4E!p`xmV#ZTV}V20?`r@LSANPRjpMk zO?)%8XjTqS zC3eMb4*Cs(;terM;~aCdvVH=RBFGj?bixAWs3J&V6pjm*s=DG9+15E?#-e9-;=3zg zM~?6A8#teejLS>Vry!wfJCVa+sHOw(W zB5j|luUX+4&S@?W#)efa&jF^@7SQz#UW_3!tz|;qrdBxhJ5}Iy1l_<##@aqk`qiD| zJQSwMdXq$DAF)0Yc4oy;A_U?xh#8(TBEQLbpM8{+eawGXGO%%tOvG(E!dbphP(DHZ z?zEK0>T;+O&{(Ficrz)yeM_-d={2EQs7~I#txi5oAcvpKYYk{#F8=kBrqHCrRDXoZ zk8K2Wsxa4|&!Z~d3V8ME{mp;=7l6k0yfq4b^pY%Ph@=>&Cn~2DKJB>p8OUO$=6;S#cidqb zJFpzi5E(lp3xp!+#?nm`boY;CMV3#p(tX0G)=tHACc81PD?5&%N0Nj^k_ZuXCll!2 zc`-XEaM@(Q=ZpDh3()8_s_s?)S0!f}4rLp+@g5{aTI@?a_9gokktr(4Qk0OLh!|^Q z8_R>FCtJhV#xletvSc^R*crPdTZ9aT2xA{6^Io3gc)z~K@!rRLxsQA1y07bho#*fT zUtdOF!6;YkuD(-buNY5lXv$`jWD1pn8akq)=Orf3NmzGQ$YnyH_k02-@INC)e>-TqD}Rq_*X~%JO9#Ruw_)V;2(1KL;SMCo| z?5gMbYWP$tefRwUc^%zF{~?;uS-55(Kr!%7Zr^k~hO@)*|<}Hf6w`!6`81_bgpjkrfT(nJD-yp={T>y$}!OT zq_t4OV=wDc2yAB2u`UWxadTp#*Il&0X0_{**=gQ0R&Ywh8}6^Lm0#xkN5-Fz3OWmC zE!H%lep^YpTEERMnk0<38sB3(5*O8R$=s4;aKls}&6B@e=9M6tK`3GmrL8jU3}j^W z-Mz&o&UqL_C{gr7>?gM@Sb0m8T*q%}pqd!?ng;L(Lll*(fZ3*>C?*Fnx8_CgZdpdOk#8;pvHBLFC}dFh46dD z*lkI#zJf2dUw|5(P~3`JB?;R<9Gng8g5-G0VI?H@KDA4_bE?d2fj?$({}AGbC6Sw3 zbgF9Dr8ry6yES^*;Ym9&OZ?4TWb%(TU$%j7J%`DayUX6u=7BeP)O)W~SFI1-8q^~V zFkiH#gj-oLLATK?ErKyR!K6#PT%X_7Pxk(MKls=Vao%Kc#v>1h?+Mbg-jhlR?cbO7 za^H|fSYllq6 zLdmDU5D28&POh7Rg6JtuyHlYdA)Z$M|A(nG)G1DXg{vjxYZmzCHUU0t!#`L8mdGr~ zm5|3+O^^u*!Edws=1Z&4le9NOAUjV%!?O^)ed?l)b%1s>Y3Pas2DcQn*)Yj5xE<`b zOQxtQf4;li;(l0Y|Ar&4TwVp6={q+7dD!7g;H=G+32DVTMPHfV)KP3N!O z(?g`XUi*FMdXwb0G{L^a%Pp-km8~7WQ7((8>69O~Fdj1rDHtV}Hy@({W<%4?^QnD? z?|U8|9hG0|Y(>2%4esi0V-a^O0z>jJs$Y1o97I^-gHv9=W-PPDZrw0x9Il(VU|BF; zrGBQ-B5W`LrmanrW#lzBy>B=oDv(Ip=n<@H!0wiLM_Kq`3FB3Uj5BfcrDYMsg~v@* zRmoUC($|TJ?ij(a?ioDXvgQTH?(S~LR*%H26(g&)_64ntU73oAzTa)v{1udO5BnMU z3O{{{?d`qa(9qy*vkw=i+6xDYFjsg}b;yG1by=Mn6RZ2Dhe>sJ*HIig-qZu1CnXlQ zLPKx(E%monmQWQTnWvVF4@S-H$OG4A7s4Uo$681G8+uZA#FHJy%WO(4t6ra!;pO%0 zW}!rWjW+jkeAfq~Ojj?jA**1`fc1r)l@Z+GuTRufJDPB|v9kM^jQ_?=yc=p~XXl-9 z;mYc2J|3SvS@pasoOVp532KL=r`ZPoyFUX@%*hcbK=Nz)$Km1oOVK~)TBEWw{1{7B zLqkJxwBw@^TRbXTGr)05?Y`9B+GIOrn>1PN#wOoPRWdKL{yB~HE3v9esGAMTY--X* znr2;xz0KE4^j-cUWE(=hQ|mRG;K1!#y0WtJa|XUKFeHMww|RWDQ5E(lcyD7iakXI< z4oNYsuC1+fXlFb=9B=mh^{vSL)t_#J$jN$eyJJ?>b#hj zbe+3zy<6-{+iqi)UwClbdPZ<_XXJsCC8s=YlMa08+3HxSikg~I_;E-9(qpzM`}_B& zYM#^GUoi$nWn~|#s@Q}WR8>_CGu7fr=@OJN{)mDci6sa%H4&WOjB4)R9Noh2{BRR$fg_iVv}C zcxJ{}I>m8)8mo1*R^>5+%Q!p?9xJhoBC7Z2+{iq+DYtu|!2N7zdAL9GTH>|YkYq5z z=33RzygKXZczIz%1F8@mhKlFArsUkqE{tF*TmAau$H4M%{>s`KQ2mK2B3u71$M5kb ziyO`3_h*iB?of8e?UY^mxu29i?ff&PVYVq$J)wQ?_Y}DKiAl44kHJKPQVeEk zM47%tp?C#CcTChgCR+M4lrz+zyhcVwC$lXsmL4m$A~BkOwt49@^N14h#Y9 zewJC)3$M5^NoS1q=-*Dq0#m6Iu>uX~izko2nL{7% zNC07_UpVBy{_+j*9oRrNaYK7hcu9=6O5gux8tRavxzRjwR*5mp3+s!Y4HS*X)6Io+2gK3nR~h&rSX4GClRn65_vl1pE`8g4^Z?=h*ADq~3(cq`s0Q%%up z28V0uAo>`C7uyZO{QXTWEqfy9&nz!5=jP`}8KlV#kBme?r@oDj`T&lFTy*S75?h<7 zh_aCBny7Hn@R?^g!^)qF!)58luvP?ZyNs3D7ziWmJKkK%Qum2WNMQXwHH8f%3->&` zEG1T2S_%d-dGtuv-TkT#Q-Z*a-gHH$iRN&~l`B_H(#SAfLC6cgK3R2U9HwZLtmxF` zz1Yi9Jq7^&x}o9v<$oEK6RD~PIzN@r$2(jW#* zy)R9E1ONyQ*GwQT+!=(~{90X|#KQx$yB)Y0!ED+UxWTUh*ScdTti14@Xd3l7()96@ zC%(tjAn?W;@Kmr9^JMj>?jR*}LqqX`9D9@jM57Bj_?J}ir%y$trGH>&=Tc>@xFKO$ z6&7*p>z*HsvwPVdXx)-d5$27r^qSRH%3zT&&I0w}Z&!G8H(zVJU%A6k5k$IEoXv!ds;x^edPlxC9){Oa$Tdmw*y9tnhO-s0usoBZrR4{};XRdslFHW6SGP*Thw z^_`)(o0k_U<9W`{g`Q+4p}^(5n1cgiVh|}iAn@R446r)Cy7xa7P6R+pBc+UmqQac{ zrlWNcVEdCC{rx@K^c=xws|lACox;{q<38?7xDv2A`5f(l66aI%u%{l73rvgLL;fKR zW;-o(BTlx`P`v%5djQelW0MA$Q3+dp0zzftbHoY%Cnxp2yyQWQIT5?!T}$0OJOIxw z$94j3I)l+dsAR%DsiNZI`NoYV`nk2qs&C)EEu@V%25h(hp+dMV_sEo*_sIDR;Rp0E z7z{YX#LVmt45n&kW(LB7udi~8vHc;BFR!66Vy=Q9kPkQoZ2H-E@qVhD&D)ESfH@}_ z0W8{qlzMbPfE-64lYmI8hP3 z7T9uAOeboy?WE5MEw8RRf!G3bR0yL60!ha@TdqxGlR?B0)mc|wq9DiQ#FI4zDVCL$ zxtw@;=c|F%-h>lyWKPf$PZM>k4|i%1un06GuP%aaVCl}w9}O_A!{vOf;{#&c70p!8 z+9e1=5-vs_ABP=p#z4M|kH=h$gih5e`pn-3`T|Ip0~V9S1k(QOXDB~sHNF3JMFq&Z z5KsYx77B&h!W!f8crD68GJwnp#BGBXIau0TU^bwr?HGf!hxdoa#!}H}WYQ3XmId%3 z*KEk8!$Q#^lPMZKp$%r1~qHttNuvUJI=Pg?Aas8JO>kJ)tv*Kq62^5SiYa{|x4_ExT`#V%h2v zy6=xHiK~C$#o;leuIlLQaN3KD!2SVU-WxfsQ3 zo}LLBcF%vF$%L0}#^!octkW-K9Qk(J+{R)lZVKAXV!q@1mCk)zPwas8XU>5HkpA)G zM@voPN6!?Yv-az+ud)|U-}W{BqvLbca8P!d_lY_s!m7*HE0U-Vw#PU}s|O*Xx4gbS z7<+e}lBKZNB@-ei!L1P?mjz$1*ZE6|J+ZBWm^HD`;W6^Ts04K1DEX*1CqM0`>DAt| zW}X7kB*FB1+6t2moA0>~XjrC=77g2t8{nW(nv0z8lW*=nqW${y>tjht!G{m8^^?VY z$n%}<30KZF_r6e|50Izw%A`g3bz7!ET;kA4cJ1&5;`Sqx`nT>cUNm%_D*<|Hdv!Jo zAUw^I?&tutfY+p~#r*yKw}8VRnVahYQ-JFP$iP_cPmFY1|2uNoiA7tf!-In@KyRNc z@nGfd$87$0b~D${JFTwZ zjmlSOd?pDFc|@Y$)I4);V&V`qR{kGw)~l0kI(2w(FkSn9KBR`96Mt;yFv=4M{vh;} N{vG4nWjgke{{z|jBXj@& literal 0 HcmV?d00001 From 5f9bd9db19cd02052ec99d7530baaf587e258397 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 05:45:41 +0000 Subject: [PATCH 32/48] Delete image.png --- images/image.png | Bin 21575 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 images/image.png diff --git a/images/image.png b/images/image.png deleted file mode 100644 index 2ded78e598dd999c33db59019adcaa8d035c2cc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21575 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 N{vG4nWjgke{{z|jBXj@& From 52209d79ba03ed41a865124c4c4547da631f8eab Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 05:47:23 +0000 Subject: [PATCH 33/48] Add files via upload --- images/2019-03-07-GoogleAuthenticatorApp.png | Bin 0 -> 7380 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/2019-03-07-GoogleAuthenticatorApp.png diff --git a/images/2019-03-07-GoogleAuthenticatorApp.png b/images/2019-03-07-GoogleAuthenticatorApp.png new file mode 100644 index 0000000000000000000000000000000000000000..d148aa11d0955cea68036fab393cd3772d2211e5 GIT binary patch literal 7380 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 BBWeHu literal 0 HcmV?d00001 From 04de98009bc9d80face1d9d56a04be2da876906b Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 06:17:38 +0000 Subject: [PATCH 34/48] Add files via upload --- ...19-03-07-GoogleAuthenticatorLoginExample.png | Bin 0 -> 16953 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/2019-03-07-GoogleAuthenticatorLoginExample.png diff --git a/images/2019-03-07-GoogleAuthenticatorLoginExample.png b/images/2019-03-07-GoogleAuthenticatorLoginExample.png new file mode 100644 index 0000000000000000000000000000000000000000..d11e27b9cb1661a58074a93e184621596038dabc GIT binary patch literal 16953 zcmch;2UJwsvNqa+h=711K|nwSL_&jrq$VmNLK74eu*m{V&N*igB!?!0geFLaCTB^K zv*aW>c9SH_TkYQWocrz>=iWQs`^PWC0o`k^syS!X{OYS(wSwL#ND~v%5Q0D;Vwu-3 zl|UdICt&;Q$P*MN=4dBCd!{_qPL7>ubq6=L-5C|9aM(&*y z@I4;>O(G&9Dk>@v2m%3tgh9eAEGz;70w9ni2m}X#%s~)11O$gb;2=p!khwVo4*!n} zAX`c*w|kUukT7sr@~_JvNjL~@4l)PE!r>5UX=zneRY`N;pQNFop{=d0i;D|LJO~7d zfIuQZl2IUd9td6uGDq=!tb!QUikmlp)OSHn;~=NGTOZLNrxhyWU5L{-lg;ik*IhUy z0uGOmc4&b+jf)2bfg?u z1iZ4+9EFmM8c_@Cc^$Z`6t)YCMr%f0=tqpfBjyYfcg<2U@Vs_&)QDB)l*89qc-|ts z@(SL#4{tm%M`3I;(Jt9&m*NG_JhUD1$}j*5~*q0BqtC_CaQdy=UJ((bhfiBCsBMl-3e z0-uaTNsge*rz_!$d2kHM{HhXu-hBJ~8_jtK>v@mx#h~KF5BS8ps%%baiMjBi&39hk~qblm`^X$W00vez_>$y;2k z+`L3#FqK#Pl~-q*vEiFB5eKN^>BhO~#+8wgsOjm-_Qkvr3~I4G2s09OH64K&L0v9} zUaq7qF6LdXeEGdm^n1GogF#(gRkpOW^z`&hOiXnAKo8HNr$<+&N4KX(Po}S?+ZPw7 z7SYq2+v5wEnPtrM=Kl2N)d&VNeYHP*_4{gcWpS|`gBiKHnqFL7+}OrkZEjy}?qe{R ztE>IrzkdVH@7kUQoE#8=)$0$oAP`9__W!j`%UpfnOKLkQH9KWXxSgY}jRD9?*Vw|2 z)55^+!86XMoIKon4~%0$Ah8sgm(SlhY3-yCSDTH07_Tz?!pr<Y#GONDrIqIARgJ@sUXk$oQr&|*<10fTf&gZ-}|B6D-jX!Mlt&C z@45NQByJU=wv%_<Cy<@v4x;nvC)dBJ5!!Je zMUrjt(;Uh2Jbx)(;iNfQo-3Um^{dv(Ay~A}JeU|Orqydf0xFXp?i|XJ{ywQ% z&onIKm)c8c2qm?R#jjudQlO~0c!bb&oHEBtINetY77C4_MhHgX|!Ct&W zyn?st61icV7RDj$v2BJOIa6%ilU8qjRqQ9eqXHJ_H*>e6A*9NTRuuVo)H$`dCOhcEKvH)X(W35^DXVe-z>#c zUFnr=awJ!(^t6Vp_L?9U}cj9c?ljGs?W`x9ab7z@*rt<1=G>uRqw7Xgiz z8|aJt`2|WmoRo4$SwD=Ntk!9%qI{Yd4a+g(RpA5EZp(s7xTWh|(`@l^g>~OJ>Y4yk zjkj*e7TedLs3=9}CNZ-kr)#gb%s8HGDXR*Kg58${F8b%W&!&nmr;2~yl|0VCTd=NO z=!MVc4~Vo7`E;~UEcYpAGP^H~H~!-Mqv*I01zw<%5*nH!e z_~pX*<%-byoy4qX4@5s{*Yti)M!s2M5 z8n=}qYfg}HN+_Oz`zGO9eT|>tGup;Q{H9&@rZ-BE*`+qA-B=z^o@u+w}%Mb(Yx zzfHaKHxqIn?}#ze@=$6pS}=pw)nw(-?UWmfCz|!m32|F9$JFZh$Z38<`rnlKiL=UctS*$0m6=Dk1OgR=m5${_1NG z?5h_Ag7Ft!5cfIL<#ij)(TY3#L_j zg_o)ypCozve86F+S>q6UzKl9-3r(}7>XRVUi)|UJcG>$72VM*!Iv$?7LEcNI7MWai zay@cn*q5rQ>1Sz7sYwC7>*T&mjyiM={O9gwO{bTN8r9Hq4)O2?CYh`QQl_rYE8JSK zGABRF!)Gy7?W~pLC2sWWss?8dR<~T+PuoK0Qt4_asl>-Czpi4JTn8*;EXwW!&f!guqTi{s^ffNg zS`Ed3blP^Z7Z=}_+DJ`mY^-@z3Vg1U-X9QlrZ-JcSC_@rry@nh7R}jxt+3nudH3Zj zXuJeoZ;tpG-M(U~)n@exNA|MoEUp{or{~ef_ImNwtk7Lt;Y?dfCqm^(T?a z1;_)cvJ$y{Txnvr6Kt%P?1D@{&X^zH1j4f=hzv@+(9t@v;R=iCO-UunU zGcx8Sl7?C%o$nQFQ#40H>ENsvTSI~~DTL$a-Li9J7oy|DCO zL&uFRKrw7mWlnT9(bZ+e%ES2IZOpgfwyIJ%DQ>G}YqLMoQ>*uE$vzl#Lo@j1TRz|u z!U+m)_UpR&d@pJ+We)8#xvob@Q26s7DdKc?$hMUre`(Pib z1itf$p5-F%zlCnK`f_+v2>7vi!7wp)Rod*NN|A>t>C^YtmI6cKtuu>Qvt%NDb?=W?ct zA;!jc_ZCa$G?3P2 z73-nJ);7kq?`?P}X3rY6FELy*MK~@MP97WMTJ{^A$U*0(-vX9Rhf7VV{BDPVsY#c; zaXsPhuDaIXX->XcOKMbEoymP3Z^ML&o9MuMw!$+xb_;j;8+{l$z0K86mi;bRoXPP| zdQI{gPrkq39_}kXU(VO(jJ(Q-oYp=tMb}cRqQ-+XexrAaop%FQaE`YGB%z0MXX^t- zxTa6!Q_t~?AFr~^S#6k#SqrZ+|DYJw`+c@k)$Lt>ranZ*pW7WiE#gu<&HWY7x8tjn zkBJr`6wHTxbCMSMk5Hq2b%#O2;4cRj$x%qd9xHK(r6 zl6MyQh>}Y$v<46v=bMCX^rWDir z;#HC!EM4v4Y6YA#pAD(WxKxTr_^1Asy{u#}oI{j@6H>>-v++IVXbJu8&aC92F$g1e;5Pqn9KE+7eRjmy!+KKGOTdf6$KoA@uHljG!|;;!e+9}+UZhdp?d z$e>(bU1=@}wNT&3rAk{_b9ns@!%C-Bz$CbDcBt155s?Vv%|^<%t-+n8_|9bnxO6*C zFx$~(l(mOP`!qYmkNmi5ena&NaUYWV<(U1g32Bg^$?wsRUm4>-?uL_yMrX<{ELY9i8A(z!e z%H8=*t5-5yJf4!JH~N({px@id=;yc#K^w>uftdT#V@iFw2$hHIVLVS~{ccypthgB& z^9?&2OJyL+wrddzR6qbo0^*%Q2I5B`K7c_M0lCPrAQ&vHAa8`~1H98-VWs?WA-IAlB}Em^t92mRsA`BlwlkJzy{XXvppN@4DNfA~H35C7;T3k+Xz~ z5BN;F8Xu-jD^lNp7L{|Ybdu0jX~v$nywPX_yo@A(C8BnX*?U@%S?+9)kTb!PRov(3 zi-oGFHf*W|bG_^u*qOW8t)J-td9h}#_4ii~pQ%Q>)`-RiiCmR1m4xqB6IJNSN{yRD z@_t3q0V-(+$*R(9TsPg~*tD|0Z&A6XKN3rr7eDw`<3fk;z#`&3nuDAYQipv_$wh)P z5D2mga*5Glr3?hlCm2k2R0;GJ3Jro0dI@A%lBb%8-uw2K6(G>3egO1`HXF7Y`-rLo zS;_woTGO{NIy^Lm0p-7F0Z^TBELjOG|AWb71CQx{N2@YO#Z*DGKWEm6CRAkII=rUa zOqU(EKT2j-Fdu*&LBcy$)df`%GuCA~;;FmzbDTL^(D3;aJ(P+rEo^uoV=y!pvP@e0 zaLkXt%Xs6o>EwGoxGQ({^xWWLC>I7jUDEePq+W%6)f?^K7$1hZgGD_SL(h~uC{bi)p79Z=^kdLY6XS5++M$>_nfN7eb%8biDOGW_1G1c}-@ z$EvHuW#ybi*nl3-fKl@h-Ip}De6)`#cYi-guVcuKHlU>wX?>i72 z^mv}`(N}xL{oxR;hspk4 zRU@T8gL{I2wYe&^_Lsxf&O7Ku+kFpMSa6%>$(LKjg-@U!7=|>>76O?t-wl6%k(f_? z?yv97=EjPXv>WC4BC>85fy-!3(N#^4a*$PeJQ?FnH%Xkm-lt=6!}en9a|k)sUaBF2NlsA9Zs%CAo`)|KcZYke|ueg6YQSYB7E$w*bM$)*I>t2qZ&xh@Qb8Y2qDt_n zK{n4kV=+DXO?8M3teZi4pmp5ZZR=rUn5{mF>6&|?1|a9N6yH22zsCt=*FQe)yXTb* zO}^4uK)B<>g2f}f9$2R{+ZT4tXv1yMG5=KMccSRM!3gtavaLNSzh4!|Pif1WKS47`qkO^H@ z&xDA_1uJK+O)Mq~B4My_%*4}d07!06*x>5~n*NkCX1(8GM^JDN2dErwTgm^40S~`? zD7)Ttpa1)`m|af%fTH^X?>ZZR4J!Bcm`gt1H0oGnYvT$e-mfH`WnDc`W;nT3O9;5k=HsOQn1pQsa_9-*PW`2bfayUc`UA$kXfA0&l_P4* zweqoqR;*bBJ7J0PfY+?lo5*llS!)HuzWNVY32z}qR;3eJw8O{?HhC9t;rYCQ2f*fA zYgIh6w$|5=`!e=Tf;Z$nwMt_lDkK+46G2UIF#Hs&3yIK2qC$_9{^Js?*;G)T-TKH! zf|o?~;osw7Ut;)kkna~uHmhj?(;h2F96vnrE~WuIOhshl)Zd!W8?5RhnMQr1mK@mj z@8=O`&8ozJbF!x%0$AnWj9_m`AGn398N6~yzU=lq$;zN(PGZ2-xmdLTkcbNMn z%ukyoTzhvZ?$jt9e-`=A2_W^tP&bNUQXyW zvu3kwk~cZG|GIU8hu1>_f3Ou;ZnsmR6PJ|4&EjF|1Y;EjVLu$ zj6=TA$pD7Iy1-&J4xG=D^-YddApm^MX7(1cP<$I73!aahA-XnlTiY$z{k_NarSo=t z;k{`oakb7H&b0A`{qn|nL&(w_Z=uwKa`*~^dN+GjLUuA33iN#IiF;Mn0#MK7At<=? zEZp#kaVED}Rp*YF8(p5jZsiniDJf)0p(jXMqwqI}F>|4UEq~H>m3j)dNmW20ze(lP z*TGhWa`r%KhDYUkSPw}cNye%N_o@?)vTEcL@AE%ZPf1FQn*(nbB`Yi|gFCUu&wN7KwCfNc5-Vbq2UhB8s_ zpf)Xup;3%AZ9;C~K9VFE^=zh;xDEwwwGVlSY_kV*7G+iCX#PJ3lD-D{Dw2U;M@ zij{S=e422p^p}DG_dU66_nJmJmcpfUqwNJXtshok9XXKH6)Uy?4x9L7;2Ej4Jtmz@2en8>? zRC<3(d;0ZV@-I00oz&)D0u&HsQ9Jdb9ukqwS+Vp+L2*1h=O*h zqFGmr-jHQ#kZBTEn!>XZUg+Vm1>hsih+x|CveM*p;(1FWZvd3=>X04%M1SEje71Po}LAH)GLmT;52w`kwH02}RlgC2eUWB-os5)q{@ z3Zwu~dJ)I>jb4-DSNhVAb5ZsWxCNjba5OA>f%tX!mGQ~3en*7q`6rl?_W*u#_%tmI zXTobzj_!><@R6gL>+?TQQ;8#-Ja+^Oa5}hfUVDkiQ1aYzP!q@B@Mr+3gjg}3tdw|9 zZj$fwW6WFKPO;R%25@SQWR9pmF^N|X7NAW6ppn8uOWb+>-Z+4>;c|8Y!R1?*gI7_V zsfjQaY7O9WJ(wO{TwvFh%>nXpx{u{MD*!iC6Z{}sp7)#@c}zUo`aFNk<~X9bPbbN9 zTn`(zdgBp`ajiGt`N{w?RuLbp0G!XOr?i!?)T%7TqU;XXKFZg_N8M}Ou%yqN>rXIv z2<;?q=I2N|#yxRc=QQ`NC!Gymsc4oYs>)`bSpwf5FJeCBYo_|6$VKi&q zcNX^=2;3d!|9(DL2oNF>l-1{hsK*d4c{_B}pkqY~K9U2nD!ks>du!gW^^%`G-LkXFqgjBCUF`dzFGAma@{@*H zr@Sbn?CzBQr&DRip^d)T+lvpV!&sIOp2dzV#{AKu-`?i zODli6t?q{B7+#ziZAVJNohM&s^k^)wFpC*%P-dbtIcnCMIQyK3w!6MVp4*jEzNPjQ|6(}%GVEXv9nG}e$WEZu7F@aMApfi1gt5LyoV99o^oHzQJcN+Ez zbh%dC!F})4%Ywxe){yRUF9*qJ&(~cDP>HRq$D+iv5sPN^q#wE~_=KYF>YU@8e>ot7 z7c!b`*!4n5kHlWG6RER7yxInmcFx@v@ZtHk1Rk0IJH#vTE}zs5uR8oo9SL`d8nvmy z@~~qXc!6iqS!V6?DPI`u+YR|be2#C~%#K6f&ZHMowKaJ|qrx;alV$^|10b}ERY`HL zrg92*pX($CS1*O#g?*Udp%eGrB?pcg_MBdn836DSU4>e25gj`R6@0j) z^+}IC*25ya5pw@$A-?fE0_Kzx%%$JJ)NXPxMp)Ph*2Z`=^6C6uluT$sT{GpVSUcbiC7%=T#SH%qngn zmFF#Tv(!CpF^<}U9*FMy+a&||uB0P`@N~(f^c0WHnW7d!3ad2(8t1{@(6N0WPx6~+ z9KiJ45+|j7%I@qiu_oCNXoOcjnEsj)kSg4*LTR+xVd4y=YcI^^4NnXL(f}S3DpLWh~HT7Z+O0Jbh83wwG-CIM30%{+aqW6#E1T|P) zI7n+_GemUw!Kyi56h1o7lTHJf@;ChBH)vm!Pgk;F+07-?_byjN155Lw?2w-GU?KU+ zwQ}PcAZn8JoO?{%(DWx4t3G#W@>xD=_oRo(uC`$#D2}XZ9+s^C+dJyG^vc|;$Ln&I z-}+?A%(1)S1NAoTu!bC+nfp^IunvfGz&SNGg_9+og54pZzQq6FfB9gLO4=ai0| zKW@QB5RAJ-%8STQ)GgJ164&}bORf|VH)!$lKq!(!R98O_k;+>0Jv~7jQF1_j>ds(> zB?0sJqpUz+?Xg*Gh=(la(2pB*7O+0}-s`>buJy|Vzt!y|hFbi{zvx!9|g_m-Q zBSr8nCgm~DPwBpG#md6sh~Fzm#1f+aCmW#^$O6Ox z%a&PJT4xg_d9r_AS-P$l*drw5e7X4%CaB9q1f*)}lwm>`bDdK+LO0q6q;9lE=?l{m zLn) z22Q>v20sAGA}z<%um|LmQerxlX^@FUHicb{4NKcOZ$>FB7eW3EPx-eaQ)_1G>R@vJ zi?JrDjfIX#rT^7XD z>_4!?g%fSz)>1xU8@b_AKDqc_sK$KbJ?BW?_eWTV&BkR}=l-$SIFF=``j~KF87A{lmp-MA!w5jAi*Bg^Ge3>JAm_ zH-i4yrv#bdD}CWMhb6hb89Wotz1k^dtmIxdZXne~9A5%^i`?;Bc-XI3!adkB48*Bz-@qd+0}_xXK)dnvWamCGJ<`H2%tG?e1iF)5 zn<-+Nqo*2YQeRK9PhUj2)6jZjs~b<@0V_QhVp8_E07n^qzc(#3u_&Q3q*OI+&fKSv zBfNFKYx8UCWObxfU(VEMURe9J=brwqYwJ;dr@#%YB{-$o9?jOl?kQ47?pir@Z!yJndouB2 zf2K5iSdg07mSG?+!AMju6u&U6pDg-PrH*Uki|9tBegS@p%Gy1=7gU*oKnnA&)w*ho zhn6_W=*j0|71gGD^c_z8CgG%sV4?R_lZYke!mKgtEv7N0DzM&SV#w5b%R5E!Bt9v@ z)?ZokmG9p-HB<$n{S+Xr3O#-D9&08(Sj3O>;l}HQKW$REJt}iiPZ{M#Z^ZoZ6i9$c znC!Gn7P20F9@46s?|82t@hrN(r6B3>90rD2cZ@f19%}pi`Eg~5)QWROK8<62F&< zA7bunD`Fc|qUCw024S$iCi>iTQAcq#OY-gabow(ZhvaANygz=58jE0xtuvk$%TP6# z_T0abjL`p)SPM-mSu3(8P6&SE;@2N)swKvat-W>>+!8GU$cC*E9=00bO#8IXEA}*R zaUU?PC1=fwur1Cl$~ESTxoIjXyUwLO?^{u{`EkY)h$1gz24$BseN2H)iB&-B*~{Ff&Tm2;4-Z9l&M zcEx$5*`;H!8&OlBn}7r6OF=y4qWg-7DEw2+ZdHp-@1*EeF(fI(7HNRW1)QpcN1RV1 z6$?mcNmQA>f>%p-KlDJra;AP%kr|YXV6yjh{S^62dt&J8_3i5!#xnrb-DWdbwgM@bJYLhQ9Vke6 z8F@!k0C=n5!aUELyrtoxMP>>V&Q?y*tH=#4*Jre(^%YeiyEiHDKKzsmTUkkhhn-b( zk{D)Y@gnk|F(XFAotKmqOg_{KEP)xpx@F=j;cNyE;wmFKhO;}*1;gsiZ1Xuh8)8iI z8U$hx8}-j7qnT+G-m+j#4P*>=4uEP9dAxkj=tes5B!#F%4S3{q8+^NrAF#G^!?en1 zlmOR8^5{I2%&5H&%KL${$0jJ60_7)yWNuA)c4KtdT3JOho;%b*?e(tL ziz3@`Y>Y~*DTTFN0JSeXAaL8e7^MTw!=b`ajQ5hrub_`4&>HE;PkdC}eDsDS{yjF(1LJDUYRD_z;r+F0HU?GT5nQcO z+GJz#%@|xbMbFx$4!}O{8lX9)!0-Q-)!j+4Z0=h$YFLS8$64|E&<=!hwXK$hnhRX^ z5t5gGF%$unl_kRc%IB(^ywk@N-ZsqzA5ZHU3XT@Kxvbwp-~WlHwE6qie5fxVN-FwJ zwbf(pH0@P02SKmE9xm(guSneU1DUYrowE(^7-P{SSyg;vgxFb5RzKu(Yf8t%E2+i^ zcJMTXpI-0)yzts}x5o!>>n0bpr>6>4J_`&Wlx>nab))WApT99_{oSt`R+nV#{m{X9 zgLv&^X|}*W=|{WP5hu$Z;$iYlW=^C5RNbETjc4q3$Ln6i>^};pd~)&MA)4H!GM(DxJ>SD!?D|u zc>kYehSFk7v#>Xy&qU#R90%v|16;NM=Y*hlXJzuedV|7K>~5UJeZKK=F0Yz7w_?y5 zIoBhR)$`o^SretgF1bhN*I#te?H{R`jlpw#lt& znao*}sy7Ct0{rP?OdI#@$f|5Dfa2<0cJ>@gSYS!oA%3;ACUvg2Oiv$l_Mt^w@Bx{b zgVTEj&f?#f)(+f5b?mf#7UPi~6B-r-xO5>wOhx|>Cmm0j17exptN zn?9udp|=?Kp^Elc`2AZW7Rhls<*oVqgTuzGnaD#DQi=eDYj&?Aql4>K7=mr8w0_!a z)CqN{JR(W)q4pB+kbG;KlBZ?$P!=+Lv$$`D5`*}jF+@2YdF$-Sd(1M3;dQ#HWe)Qp ze$^X#3Br_j&^NiV?;wJRB06Z`yMb>HjKB8=N?K`s6Kz&ci0dxdcO%rH1(*o|@NBoj zi+qK+7D&idUuGlAitoSSVX<+g;(qW5S7YfZ^a0L)rXmY2yWMq47{WqmA%%WQo#Tg&K8-!5Ut?0|8(|7B?YM%|^ z&a`h8weB9#pho8yj8tb_WXM?#bVtc_0#%o1dzvf+s^`NDjN{Pi8q)WbWYtKGDYMl9nbrw1`pfjgr?1a=u40S`gopVubySw>{VLBB z6vwT%m~{@KL=r9jNMBm6Tp3YPfw~KvhuDP;g&N~42ybk*_Tg3EJhJ~(lDe^rlr+4N z#jQfHu7y6WXM)~WWpUTzPKjHc{`tzqX!hY?AjcE35wg)Wv`E~KL_NN31MVX)XU>$k zm*%0l%-(cbq3k_#>Np8^gPxtW0*xUXgOKMp_lJ!{%;*MSuF{!|y(-aJ_HGj$Th-hS z;LtrW$1{uQ#->r3+9gK!txk2WF4N{;jRiGlHubE(Wc${Tt@@rKbc+Y_cCWTr&Xt{6 zpD>P?g;^~|E9^Xvc{48-HZm5Z7y-0um}ehE*||RzrMHr$TPGvUIv6%9i)%(e?U{k# zU{-@$(#pP%6wHOP#Wi&k<1O5%z9IHKvtY(6WTWN(8Sn&SM66tpR59uhlB^U+$|M(W! zy!HMqZr$*;#4c54WxC6tr0wj};d)asHY>y68R>gjRNWhb;$9Uy<{z=y2Avn3mVebD z&<|_B-|d6AFO3KL`cfOiB?ZR`vO7vMW}h_evMxg#o8Ro%s6TjDe9_39`4Vb6RQXv( zXtx1lcLqypp%2T9%O`FXOtDR^(b!Lz6SFrlrpWFL?5xo62n!Fe*X%%i11|0sIGM^! zRw5ioIyT&FkuIf7*d8Lm6w|p!pOKr!tR{Jc9UCGCyISZ5_Sb)Xx_^*5H!Li_`qx11 zUG?{}f8yI(Y_#i3*?f%!KPm+%SFhu9JV3j$$4b~7xW|$N^W7wGe#%tyoHi&w-P1() z@~OgF^zqzqokn9ItKustz7vRj8oe^4=-9Z}>y1@+sVY3w@>&en za;a;0;+y0{6RKM$>ToVWwJzOjUSr0LfJI;?=Vl4_fRlJq@G-+lWG&J;!8y zth~f%9v=0>TLtp^7nuNT1kMw)I1?ywLrLZi1WU@^Q;>8oOw?p~nZ|7b-FN zbyNcELBQz4qKfJDmRy~^X2Q+te*SICc(!y2S z#*smsT5F@O81v5ga~BRZxXY*uNjQ(@OAP6pkoj^fT$?mQLq~o3+exIO-{-U&9)(K3 zb?4LTkDC@O-Wg8fO*_iN?lx`iN&OeDJbrncZmY1L9*e&EBB^pTeF+xMxG>MJ^YnN@ zltm4*JM+~7<2zq^cA0PbSx=F0c_9>bTgyHrZ19rK+J5k}JMB{(xdSwuT69c~v*TLm z*~7l|Ro#;}o5O2FSQT5S>t{t1SLN#vWWo~B%48|)eN)Y=%pq2Hk1rjpS)-KB&*-e} zqXM4EHc_%Q45>JhPK4!>foq&^o*&pHW;l%dSu3ShdzEV)e?L4uN5}Tc|MYp!Fg-pT zsIOEjjlSlz>WfyPJF=)N>t?VaQX3@u#bZsCECKGab@L35yU%$tDHn%?=*b{hgVK(JXrQwSJS;_Uje&WToOZj`}+HFuBQnaQqxm*J-P zpdnzRL+khs?QBC3=Z>7Z={G@E1!#D~w)x?kpmObW5lZ|N5I`I$pUD>=S|Xe`vK|)p zlF{mgo%`|5+wv^#sMvRBnuxw^yN}7Jz_P?BTzck|NRdZ*iC1fC|!cQhLhy4@L^WMA45LvR`qc6Z4TtTW_HzAer&&(a4llVVL3#zo9# zM#KEWFFQ^_6c2<6JAbh*4w@&~qrN7^J@xO}x@>U2oDO~cqXF!D@gNN4qOacN7Ij zFA|gKh0HC~L+Z=%TLf7xcKX<9{f?UDfj0@>4k}xAKsNdVHzSlTCiz$^QKFtToc$aC^0%Nw1^QZE6Jy$^ z3f&oq)F$ysXRvPJ;UVF)92@pUKVWRdGxu#~;d2P5|Brow2iY^1u{|p%L2?iPYpDuc#wNziKttS3;9^-V!UpJ@yAFIG z1cPWkRS=dL9p3PLfcv6m#F4)#SQ+J!#X~El)-$;%4lNDh?VyWIv>kaJP4g#qH5eMl<`RuP?$?)>iWA8 zU14@x00*ZDLYAAaA>93VVX}fZz#AP7(Nq}kV|K|>C<_}D|4Sp2Pqr)A#z{)}p%M{b5 zD?SJ&ZH}*}4yAiQ_q4Uv6d|zqpT?{}e`aX2;11JUXb#c8Zc^pfKTV=IuS{4bix2@= z<0=Wu)OVzC-pfhRcZJb}X16+p=KHiv$pAyEwZ8fRf0g75U#4}|dqf^|dD1@s6cFCa znO)Y0q)c3itR6KHFc&ghe~i@Ca8+$}N@2%gc;-i5Y|Y*b{QZLEaV5|SEFoz>r?&Q1 cG3SaQfMuC6jN2LeraMSRO5tVE3mu>T2Ye4 Date: Thu, 7 Mar 2019 06:54:04 +0000 Subject: [PATCH 35/48] Create 2019-03-07-Google-Authenticator-In-PowerShell.md --- ...3-07-Google-Authenticator-In-PowerShell.md | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 _posts/2019-03-07-Google-Authenticator-In-PowerShell.md diff --git a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md new file mode 100644 index 0000000000000..45934585a0753 --- /dev/null +++ b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md @@ -0,0 +1,99 @@ +--- +layout: post +title: Google Authenticator in PowerShell +date: 2019-03-07 +tags: [PowerShell] +--- + +Relevant links: + - [This blog post's PowerShell code - GoogleAuthenticator.psm1](https://github.com/HumanEquivalentUnit/PowerShell-Misc/blob/master/GoogleAuthenticator.psm1) + - [An online QR code reader](https://webqr.com/) - click the 'still camera' icon on the top right, then you can drag QR codes to it. + - [Google Authenticator app on iTunes store](https://itunes.apple.com/gb/app/google-authenticator/id388497605?mt=8) (optional) + - [Google Authenticator app on Play store](https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2) (optional) + +Google Authenticator is a 2-Factor Authentication (2FA) system, +with an app that generates codes like this: + +![Google Authenticator iPhone App Screenshot](images/2019-03-07-GoogleAuthenticatorApp.png) + +I wanted to generate that PIN code in PowerShell. + + +---- + +A basic website login has a username and password; +anyone in the world who steals your password can get into your account. +Google Authenticator 2FA adds another code from a smartphone app, +and now anyone logging in needs to know your password *and* have your smartphone. + +Behind the scenes, there is another secret stored against your user account and shared between the server and your smartphone. +It gets there through a QR code, here's an example of a basic logon and enabling 2FA: + +![Example of basic website logon form vs combined 2FA signup and logon form](images/2019-03-07-GoogleAuthenticatorLoginExample.png) + +If you have a signup for one of these Google 2FA sites, +visit the online QR code reader linked above +and see that the QR code contains [text in the Key Uri format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format) like this: + + otpauth://totp/{accountName}?secret={code}&issuer={companyName} + +The first thing this PowerShell module can do is generate one of these random secrets, +in this form, with a link to Google Chart API to show it as a QR code. + +```powershell +PS C:\> Import-Module c:\temp\GoogleAuthenticator.psm1 +PS C:\> $Secret = New-GoogleAuthenticatorSecret -Online # online will open a browser window +PS C:\> $Secret | Format-List + +Secret : XSFOC6D37UW6JOJ5 +QrCodeUri : http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=otpauth%3A%2F%2Ftotp%2FExample%2520Website%253Aal + ice%2540example.com%3Fsecret%3DXSFOC6D37UW6JOJ5%26issuer%3DExample%2520Corp +``` + +You can scan the QR code in the app to add your new token. + + +Once you have the secret, you can generate the current PIN code for it: + +```powershell +PS C:\> $Secret | Get-GoogleAuthenticatorPin | Format-List + +PIN Code : 030 191 +Seconds Remaining : 27 +``` + +I do not know of a way to get the secret out of the Google Authenticator app, +but it does have a bit of a weakness - if you are enabling 2FA +you can scan the QR code with as many devices as you want and they will all generate the same PIN codes. + +So disable/re-enable, or reset, 2FA on your account (careful not to lock yourself out), +setup your normal login again with a new QR code and add that to the app - but also take a copy. +Now you can get the secret out of the QR code URL, +and generate the PIN from PowerShell. + +NB. that this is a lot like having a password in plain text, +and should be treated as carefully - store it somewhere safe, preferably an encrypted password vault, etc. + +Playing with this code / the QrCodeUri and Google Charts would also let you +add your serious website secret to the app, but with a more amusing name. + +---- + +On the PowerShell side of things, I started out with [this StackExchange explanation](https://security.stackexchange.com/a/135953) of the algorithm, +and trying to port [this GoLang code](https://github.com/robbiev/two-factor-auth), +and after getting code which looked OK but generated the wrong output, +I worked from [this C# code](https://stackoverflow.com/questions/6421950/is-there-a-tutorial-on-how-to-implement-google-authenticator-in-net-apps) + +The algorithm itself is not enormously complex, but I did trip over a lot of minor problems: + + - Intel CPUs / dotnet on Windows is little-endian byte order, the algorithm needs big-endian byte order + - Base32 encoding is involved and that means turning 8-bit-bytes into 5-bit-chunks, and I didn't want to write a whole lot of bit manipulation. + - BigInteger class helped, but it stores bytes little-endian inside and has occasional padding for handling two's complement negative numbers. + - After trying some combinations of BitConverter, and starting to port a page of C# code just for byte work, I switched to use regex and "binary" strings instead. + - `[BitConverter]::GetBytes($time)` was trying to hit the overload for `[char]` until I added a `[int64]` type, and it was sometimes working. + - I can't type the alphabet correctly and put "VXWYZ", so some codes would sometimes cause the wrong output. + - dotNet has a mess of methods for URI Encoding, [8 different ones](https://stackoverflow.com/a/21771206) for different framework versions, which are variously broken, incompatible with RFCs, or non-standard. + - (I'm not sure I picked a good one) + +NB. Google Authenticator app, and the TOTP protocol support more than I have coded - other window sizes, other hash algorithms. + From 3ccf84c37601c86ab6b59103b1cbbc5be8a863ce Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 06:58:49 +0000 Subject: [PATCH 36/48] fix image urls --- _posts/2019-03-07-Google-Authenticator-In-PowerShell.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md index 45934585a0753..b9f003b287f1c 100644 --- a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md +++ b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md @@ -14,7 +14,7 @@ Relevant links: Google Authenticator is a 2-Factor Authentication (2FA) system, with an app that generates codes like this: -![Google Authenticator iPhone App Screenshot](images/2019-03-07-GoogleAuthenticatorApp.png) +![Google Authenticator iPhone App Screenshot](/images/2019-03-07-GoogleAuthenticatorApp.png) I wanted to generate that PIN code in PowerShell. @@ -29,7 +29,7 @@ and now anyone logging in needs to know your password *and* have your smartphone Behind the scenes, there is another secret stored against your user account and shared between the server and your smartphone. It gets there through a QR code, here's an example of a basic logon and enabling 2FA: -![Example of basic website logon form vs combined 2FA signup and logon form](images/2019-03-07-GoogleAuthenticatorLoginExample.png) +![Example of basic website logon form vs combined 2FA signup and logon form](/images/2019-03-07-GoogleAuthenticatorLoginExample.png) If you have a signup for one of these Google 2FA sites, visit the online QR code reader linked above From 2519f462c87f971761bcaedf2708f6badf922bcc Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 18:10:05 +0000 Subject: [PATCH 37/48] update --- ...3-07-Google-Authenticator-In-PowerShell.md | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md index b9f003b287f1c..a5113fc8c54cb 100644 --- a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md +++ b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md @@ -5,6 +5,16 @@ date: 2019-03-07 tags: [PowerShell] --- +```powershell +PS C:\> Import-Module c:\downloads\GoogleAuthenticator.psm1 +PS C:\> Get-GoogleAuthenticatorPin -Secret XSFOC6D37UW6JOJ5 | Format-List + +PIN Code : 030 191 +Seconds Remaining : 27 +``` + +But where do you get that secret code? + Relevant links: - [This blog post's PowerShell code - GoogleAuthenticator.psm1](https://github.com/HumanEquivalentUnit/PowerShell-Misc/blob/master/GoogleAuthenticator.psm1) - [An online QR code reader](https://webqr.com/) - click the 'still camera' icon on the top right, then you can drag QR codes to it. @@ -35,10 +45,15 @@ If you have a signup for one of these Google 2FA sites, visit the online QR code reader linked above and see that the QR code contains [text in the Key Uri format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format) like this: - otpauth://totp/{accountName}?secret={code}&issuer={companyName} +``` +otpauth://totp/{accountName}?secret={code}&issuer={companyName} + ^ + this is the secret +``` The first thing this PowerShell module can do is generate one of these random secrets, -in this form, with a link to Google Chart API to show it as a QR code. +wrap it in this `otpauth://` style link, +then embed that in a link to Google Charts to show the whole thing as a QR code. ```powershell PS C:\> Import-Module c:\temp\GoogleAuthenticator.psm1 @@ -52,8 +67,9 @@ QrCodeUri : http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=otpauth%3A You can scan the QR code in the app to add your new token. - -Once you have the secret, you can generate the current PIN code for it: +Once you have the secret code, +either generating your own (for fun) or taken from a real website's QR code for your account, +you can generate the current PIN code for it: ```powershell PS C:\> $Secret | Get-GoogleAuthenticatorPin | Format-List @@ -76,6 +92,17 @@ and should be treated as carefully - store it somewhere safe, preferably an encr Playing with this code / the QrCodeUri and Google Charts would also let you add your serious website secret to the app, but with a more amusing name. +Re-do your 2FA to get a new QR code, and get the `otpauth://` text out of it, and get the secret code. + +Generate a new code with your custom username and company name to show up in the app: + +```powershell +PS C:\> New-GoogleAuthenticatorSecret -Name 'My Login!' -Issuer 'Some Company' | % QrCodeUri +https://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=otpauth%3A%2F%2Ftotp%2FMy%2520Login%2521%3Fsecret%3D6HHNKDJM5RWHBHJY%26issuer%3DSome%2520Company +``` + +Then swap the secret part after `secret%3D` with your real code (%3D is = so leave that in), +visit that in a browser, scan into the app - a working login, with custom text. ---- @@ -84,16 +111,16 @@ and trying to port [this GoLang code](https://github.com/robbiev/two-factor-auth and after getting code which looked OK but generated the wrong output, I worked from [this C# code](https://stackoverflow.com/questions/6421950/is-there-a-tutorial-on-how-to-implement-google-authenticator-in-net-apps) -The algorithm itself is not enormously complex, but I did trip over a lot of minor problems: +The algorithm itself is not very complex, but I did trip over a lot of minor problems: - Intel CPUs / dotnet on Windows is little-endian byte order, the algorithm needs big-endian byte order - Base32 encoding is involved and that means turning 8-bit-bytes into 5-bit-chunks, and I didn't want to write a whole lot of bit manipulation. - BigInteger class helped, but it stores bytes little-endian inside and has occasional padding for handling two's complement negative numbers. - After trying some combinations of BitConverter, and starting to port a page of C# code just for byte work, I switched to use regex and "binary" strings instead. - `[BitConverter]::GetBytes($time)` was trying to hit the overload for `[char]` until I added a `[int64]` type, and it was sometimes working. - - I can't type the alphabet correctly and put "VXWYZ", so some codes would sometimes cause the wrong output. + - I can't type the alphabet correctly and put "VXWYZ", so some codes which included X or W would cause the wrong output. - dotNet has a mess of methods for URI Encoding, [8 different ones](https://stackoverflow.com/a/21771206) for different framework versions, which are variously broken, incompatible with RFCs, or non-standard. - (I'm not sure I picked a good one) -NB. Google Authenticator app, and the TOTP protocol support more than I have coded - other window sizes, other hash algorithms. +NB. Google Authenticator app, and the TOTP protocol support more features than I have coded - other window sizes, other hash algorithms. From f67911334c5996761ad32b8c33ba18322b9af285 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 19:21:26 +0000 Subject: [PATCH 38/48] Add KeyUri example --- _posts/2019-03-07-Google-Authenticator-In-PowerShell.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md index a5113fc8c54cb..8fb7556b346be 100644 --- a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md +++ b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md @@ -61,6 +61,7 @@ PS C:\> $Secret = New-GoogleAuthenticatorSecret -Online # online will open a PS C:\> $Secret | Format-List Secret : XSFOC6D37UW6JOJ5 +KeyUri : otpauth://totp/Example%20Website%3Aalice%40example.com?secret=XSFOC6D37UW6JOJ5&issuer=Example%20Corp%20%F0%9F%98%83 QrCodeUri : http://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=otpauth%3A%2F%2Ftotp%2FExample%2520Website%253Aal ice%2540example.com%3Fsecret%3DXSFOC6D37UW6JOJ5%26issuer%3DExample%2520Corp ``` From 874d287350fca9e486bcbec671ed5505338dfcdb Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 19:30:59 +0000 Subject: [PATCH 39/48] update for custom text tweak --- ...9-03-07-Google-Authenticator-In-PowerShell.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md index 8fb7556b346be..7aeccf11d9611 100644 --- a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md +++ b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md @@ -93,17 +93,19 @@ and should be treated as carefully - store it somewhere safe, preferably an encr Playing with this code / the QrCodeUri and Google Charts would also let you add your serious website secret to the app, but with a more amusing name. -Re-do your 2FA to get a new QR code, and get the `otpauth://` text out of it, and get the secret code. - -Generate a new code with your custom username and company name to show up in the app: +Re-do your 2FA on an account to get a new QR code, +and get the `otpauth://` text out of it, and pic the secret code out of that, +then generate a new QR code for it with your custom username and company name to show up in the app: ```powershell -PS C:\> New-GoogleAuthenticatorSecret -Name 'My Login!' -Issuer 'Some Company' | % QrCodeUri -https://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=otpauth%3A%2F%2Ftotp%2FMy%2520Login%2521%3Fsecret%3D6HHNKDJM5RWHBHJY%26issuer%3DSome%2520Company +PS C:\> New-GoogleAuthenticatorSecret -UseThisSecretCode HP44SIFI2GFDZHT6 -Name "me@example.com" -Issuer "My bank 💎" -Online | fl * + +Secret : HP44SIFI2GFDZHT6 +KeyUri : otpauth://totp/me%40example.com?secret=HP44SIFI2GFDZHT6&issuer=My%20bank%20%F0%9F%92%8E +QrCodeUri : https://chart.apis.google.com/chart?cht=qr&chs=200x200&chl=otpauth%3A%2F%2Ftotp%2Fme%25[..] ``` -Then swap the secret part after `secret%3D` with your real code (%3D is = so leave that in), -visit that in a browser, scan into the app - a working login, with custom text. +web browser opens, and you can scan your bank code into the app, with new text around it. ---- From 5c8dc3817c3a82366b29e9bb9326632f630db36c Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 19:35:30 +0000 Subject: [PATCH 40/48] tweak authparams bit to use splatting so diamond is visible without sideways scrolling --- _posts/2019-03-07-Google-Authenticator-In-PowerShell.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md index 7aeccf11d9611..b5fce8cda8e91 100644 --- a/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md +++ b/_posts/2019-03-07-Google-Authenticator-In-PowerShell.md @@ -98,7 +98,14 @@ and get the `otpauth://` text out of it, and pic the secret code out of that, then generate a new QR code for it with your custom username and company name to show up in the app: ```powershell -PS C:\> New-GoogleAuthenticatorSecret -UseThisSecretCode HP44SIFI2GFDZHT6 -Name "me@example.com" -Issuer "My bank 💎" -Online | fl * +PS C:\> $authParams = @{ + UseThisSecretCode = 'HP44SIFI2GFDZHT6' + Issuer = "My bank 💎" + Name = "me@example.com" + Online = $true +} + +PS C:\> New-GoogleAuthenticatorSecret @authParams | fl * Secret : HP44SIFI2GFDZHT6 KeyUri : otpauth://totp/me%40example.com?secret=HP44SIFI2GFDZHT6&issuer=My%20bank%20%F0%9F%92%8E From fefff9099bf57076a3a4418e318bf098f8113d05 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 7 Mar 2019 21:13:55 +0000 Subject: [PATCH 41/48] Create 2019-03-08-Base32-coding-the-scripting-way.md --- ...9-03-08-Base32-coding-the-scripting-way.md | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 _posts/2019-03-08-Base32-coding-the-scripting-way.md diff --git a/_posts/2019-03-08-Base32-coding-the-scripting-way.md b/_posts/2019-03-08-Base32-coding-the-scripting-way.md new file mode 100644 index 0000000000000..030484ef37ed7 --- /dev/null +++ b/_posts/2019-03-08-Base32-coding-the-scripting-way.md @@ -0,0 +1,220 @@ +--- +layout: post +title: Base32 encoding and decoding, the scripting way +date: 2019-03-08 +tags: [PowerShell] +--- + +For my previous [Google Authenticator post](https://humanequivalentunit.github.io/Google-Authenticator-In-PowerShell/), +the secret codes involved (e.g. `5WYYADYB5DK2BIOV`) are BASE32 encoded data. +I want to write about how I did that in Powershell, +but you might need to know what an encoding is first. + +If you know about encodings, [skip over this next part](#skipped-encoding). + +#### How do you pass a blob of data through the internet? + +A file upload site, yes, +but wouldn't it be convenient if you could send files through email, forums, blog posts, +and use *text* processing tools on them? + + + +You can take any file, treat it as a sequence of bytes, +each of those is 8-bits, which is also a number 0-255: + +```powershell +PS C:\> get-content c:\windows\system32\calc.exe -Encoding Byte | + select -First 3 +77 +90 +144 + +PS C:\> get-content c:\windows\system32\calc.exe -Encoding Byte | + select -First 3 | + foreach { [convert]::ToString($_, 2).padleft(8, '0') } +01001101 +01011010 +10010000 +``` + +Roughly speaking, if you split a byte in half, +each half can be numbers 0-15. +Use "A = 1, B = 2, C = 3" and find the letters for each half: + +```powershell +10101101 (one hundred and seventy three) +1010 1101 +(ten) (thirteen) + J M +``` + +Now you have the byte value 173 turned into the text `JM`, +and can send it over any text tool, any forum, any source control +as long as you can undo this, and get the bytes back. +This process is used for things like SSL certificates, +the stuff inside here is BASE64 encoded: + + -----BEGIN CERTIFICATE----- + MIIF2zCCBMOgAwIBAgIQMj8HjgweXk + +The real BASE64 and BASE32 do not split bytes in half, +because they can do better and the output won't be so much bigger. + +#### Skipped encoding intro + +For BASE32 encoding you take 5-bits at a time, +treat them as numbers 0-31, +and look them up in the character set `'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'`. +For decoding you do this backwards, +character to charset position, to 5-bit value. + +This is a right pain, +look at how 5-bit chunks do not line up nicely with 8-bit bytes: + +``` +$bytes = [byte[]] @( 77, 90, 144 ) +01001101 01011010 10010000 +||||| + ||| || + ||||| + | |||| + ... +``` + +Keeping track of how many bits you have taken from each byte, +doing the bit-manipulation to take some bits out of one byte and out of another and combining them, +is a lot of careful book-keeping. +Proper software developers will care about what happens if there aren't enough. + +Take a cutting from [this C# code](https://stackoverflow.com/a/7135008) to turn a byte array to a BASE32 string: + +```csharp +public static string ToString(byte[] input) +{ + int charCount = (int)Math.Ceiling(input.Length / 5d) * 8; + char[] returnArray = new char[charCount]; + + byte nextChar = 0, bitsRemaining = 5; + int arrayIndex = 0; + + foreach (byte b in input) + { + nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining))); + returnArray[arrayIndex++] = ValueToChar(nextChar); + + if (bitsRemaining < 4) + { + nextChar = (byte)((b >> (3 - bitsRemaining)) & 31); + returnArray[arrayIndex++] = ValueToChar(nextChar); + bitsRemaining += 5; + } + + bitsRemaining -= 3; + nextChar = (byte)((b << bitsRemaining) & 31); + } + + return new string(returnArray); +} +``` + +Read it and tell me if there are any off-by-one errors or weird edge cases. + +No no no, up here in scripting land we have plenty of CPU to waste. +We're going to use strings and regex. + +```powershell +[byte[]] $bytes = @(188, 138, 225, 120, 123, 253, 45, 228, 185, 61) + +$byteArrayAsBinaryString = -join $bytes.ForEach{ + [Convert]::ToString($_, 2).PadLeft(8, '0') + } + +$Base32Secret = [regex]::Replace($byteArrayAsBinaryString, '.{5}', { + param($Match) + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'[[Convert]::ToInt32($Match.Value, 2)] + }) + +# XSFOC6D37UW6JOJ5 +``` + +The regex `.{5}` picks out five "bits" at a time, +and there's two calls to `[convert]` to go between numbers and strings-representing-binary. + +As long as there are a multiple of 5 bits in the byte array, +which is fine for my use case. +It's horrendously inefficient if we were encoding megabytes of data, +but this is only ten bytes, it's fast enough. + +#### Decoding +---- + +and the C# code to go back the other way, +BASE32 string to byte array is as long and full of bookkeeping: + +```c-sharp +public static byte[] ToBytes(string input) +{ + + input = input.TrimEnd('='); //remove padding characters + int byteCount = input.Length * 5 / 8; //this must be TRUNCATED + byte[] returnArray = new byte[byteCount]; + + byte curByte = 0, bitsRemaining = 8; + int mask = 0, arrayIndex = 0; + + foreach (char c in input) + { + int cValue = CharToValue(c); + + if (bitsRemaining > 5) + { + mask = cValue << (bitsRemaining - 5); + curByte = (byte)(curByte | mask); + bitsRemaining -= 5; + } + else + { + mask = cValue >> (5 - bitsRemaining); + curByte = (byte)(curByte | mask); + returnArray[arrayIndex++] = curByte; + curByte = (byte)(cValue << (3 + bitsRemaining)); + bitsRemaining += 3; + } + } + + return returnArray; +} +``` + +and the PowerShell would be shorter by using BigInteger to make combining 5-bits at a time easier, +but nothing is quite as simple as I hope and there are two catches involved: + +```powershell + $bigInteger = [Numerics.BigInteger]::Zero + + foreach ($char in ($secret.ToUpper() -replace '[^A-Z2-7]').GetEnumerator()) { + $bigInteger = ($bigInteger -shl 5) -bor ('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'.IndexOf($char)) + } + + [byte[]]$secretAsBytes = $bigInteger.ToByteArray() + + + # BigInteger sometimes adds a 0 byte to the end, + # if the positive number could be mistaken as a two's complement negative number. + # If it happens, we need to remove it. + if ($secretAsBytes[-1] -eq 0) { + $secretAsBytes = $secretAsBytes[0..($secretAsBytes.Count - 2)] + } + + + # BigInteger stores bytes in Little-Endian order, + # but we need them in Big-Endian order. + [array]::Reverse($secretAsBytes) +``` + +The C# could do this as well. + +Anyway, the BASE32 regex was quite fun, +and now you know where my comment "I can't write the alphabet" from the previous blog post fits in, +and why it broke my encoding/decoding. From 0d9b552dce70e0b624f5cff7a14c4680c6383905 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Fri, 8 Mar 2019 01:14:27 +0000 Subject: [PATCH 42/48] fix skip anchor link --- _posts/2019-03-08-Base32-coding-the-scripting-way.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2019-03-08-Base32-coding-the-scripting-way.md b/_posts/2019-03-08-Base32-coding-the-scripting-way.md index 030484ef37ed7..022ed28c58e63 100644 --- a/_posts/2019-03-08-Base32-coding-the-scripting-way.md +++ b/_posts/2019-03-08-Base32-coding-the-scripting-way.md @@ -10,7 +10,7 @@ the secret codes involved (e.g. `5WYYADYB5DK2BIOV`) are BASE32 encoded data. I want to write about how I did that in Powershell, but you might need to know what an encoding is first. -If you know about encodings, [skip over this next part](#skipped-encoding). +If you know about encodings, [skip over this next part](#skipped-encoding-intro). #### How do you pass a blob of data through the internet? From 1855447be60fffbabe78a9198ef922a71475e379 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Wed, 1 May 2019 10:03:01 +0100 Subject: [PATCH 43/48] Blog entry about VSS and jborean93's module --- .../2019-04-30-Get-SnapshotPath.psm1.txt | 273 ++++++++++++++++++ _posts/2019-04-30-VSS-from-server-share.md | 36 +++ 2 files changed, 309 insertions(+) create mode 100644 _includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt create mode 100644 _posts/2019-04-30-VSS-from-server-share.md diff --git a/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt b/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt new file mode 100644 index 0000000000000..2df4187de66ee --- /dev/null +++ b/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt @@ -0,0 +1,273 @@ +# Cloned from https://gist.github.com/jborean93/f60da33b08f8e1d5e0ef545b0a4698a0 + +# Copyright: (c) 2019, Jordan Borean (@jborean93) +# MIT License (see LICENSE or https://opensource.org/licenses/MIT) + +# To use, copy the .psm1 file locally and run +# Import-Module -Name Get-SnapshotPath.psm1 +# Get-SnapshotPath -Path "\\server\share" + +Add-Type -TypeDefinition @' +using Microsoft.Win32.SafeHandles; +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.AccessControl; + +namespace Win32 +{ + public class NativeHelpers + { + [StructLayout(LayoutKind.Sequential)] + public struct IO_STATUS_BLOCK + { + public UInt32 Status; + public UInt32 Information; + } + + [StructLayout(LayoutKind.Sequential)] + public struct NT_Trans_Data + { + public UInt32 NumberOfSnapShots; + public UInt32 NumberOfSnapShotsReturned; + public UInt32 SnapShotArraySize; + // Omit SnapShotMultiSZ because we manually get that string based on the struct results + } + } + + public class NativeMethods + { + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern SafeFileHandle CreateFileW( + string lpFileName, + FileSystemRights dwDesiredAccess, + FileShare dwShareMode, + IntPtr lpSecurityAttributes, + FileMode dwCreationDisposition, + UInt32 dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern UInt32 NtFsControlFile( + SafeFileHandle hDevice, + IntPtr Event, + IntPtr ApcRoutine, + IntPtr ApcContext, + ref NativeHelpers.IO_STATUS_BLOCK IoStatusBlock, + UInt32 FsControlCode, + IntPtr InputBuffer, + UInt32 InputBufferLength, + IntPtr OutputBuffer, + UInt32 OutputBufferLength); + + [DllImport("ntdll.dll")] + public static extern UInt32 RtlNtStatusToDosError( + UInt32 Status); + } +} +'@ + +Function Get-LastWin32ExceptionMessage { + <# + .SYNOPSIS + Converts a Win32 Status Code to a more descriptive error message. + + .PARAMETER ErrorCode + The Win32 Error Code to convert + + .EXAMPLE + $LastError = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + Get-LastWin32Exception -ErrorCode $LastError + #> + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [System.Int32] + $ErrorCode + ) + + $Exp = New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $ErrorCode + $ExpMsg = "{0} (Win32 ErrorCode {1} - 0x{1:X8})" -f $Exp.Message, $ErrorCode + return $ExpMsg +} + +Function Invoke-EnumerateSnapshots { + <# + .SYNOPSIS + Invokes NtFsControlFile with the handle and buffer size specified. + + .DESCRIPTION + This cmdlet is defined to invoke NtFsControlFile with the + FSCTL_SRV_ENUMERATE_SNAPSHOTS control code. + + .PARAMETER Handle + A SafeFileHandle of the opened UNC path. This should be retrieved with + CreateFileW. + + .PARAMETER BufferSize + The buffer size to initialise the output buffer. This should be a minimum + of ([System.Runtime.InteropServices.Marshal]::SizeOf([Type][Win32.NativeHelpers+NT_Trans_Data]) + 4). + See Examples on how to invoke this + + .PARAMETER ScriptBlock + The script block to invoke after the raw output buffer is converted to the + NT_Trans_Data structure. + + .EXAMPLE + $BufferSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][Win32.NativeHelpers+NT_Trans_Data]) + 4) + Invoke-EnumerateSnapshots -Handle $Handle -BufferSize $BufferSize -ScriptBlock { + $TransactionData = $args[1] + + if ($TransactionData.NumberOfSnapShots -gt 0) { + $NewBufferSize = $BufferSize + $TransactionData.SnapShotArraySize + + Invoke-EnumerateSnapshots -Handle $Handle -BufferSize $NewBufferSize -ScriptBlock { + $OutBuffer = $args[0] + $TransactionData = $args[1] + + $SnapshotPtr = [System.IntPtr]::Add($OutBuffer, $TransDataSize) + $SnapshotString = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($SnapshotPtr, + $TransactionData.SnapShotArraySize / 2) + + $SnapshotString.Split([char[]]@("`0"), [System.StringSplitOptions]::RemoveEmptyEntries) + } + } + } + #> + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [Microsoft.Win32.SafeHandles.SafeFileHandle] + $Handle, + + [Parameter(Mandatory = $true)] + [System.Int32] + $BufferSize, + + [Parameter(Mandatory = $true)] + [ScriptBlock] + $ScriptBlock + ) + + # Allocate new memory based on the buffer size + $OutBuffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($BufferSize) + try { + $IOBlock = New-Object -TypeName Win32.NativeHelpers+IO_STATUS_BLOCK + + # Call NtFsControlFile with the handle and FSCTL_SRV_ENUMERATE_SNAPSHOTS code + $Result = [Win32.NativeMethods]::NtFsControlFile($Handle, [System.IntPtr]::Zero, [System.IntPtr]::Zero, + [System.IntPtr]::Zero, [Ref]$IOBlock, 0x00144064, [System.IntPtr]::Zero, 0, $OutBuffer, $BufferSize) + + if ($Result -ne 0) { + # If the result was not 0 we need to convert the NTSTATUS code to a Win32 code + $Win32Error = [Win32.NativeMethods]::RtlNtStatusToDosError($Result) + $Msg = Get-LastWin32ExceptionMessage -ErrorCode $Win32Error + Write-Error -Message "NtFsControlFile failed - $Msg" + return + } + + # Convert the OutBuffer pointer to a NT_Trans_Data structure + $TransactionData = [System.Runtime.InteropServices.Marshal]::PtrToStructure( + $OutBuffer, + [Type][Win32.NativeHelpers+NT_Trans_Data] + ) + + # Invoke out script block that parses the data and outputs whatever it needs. We pass in both the + # OutBuffer and TransactionData as arguments + &$ScriptBlock $OutBuffer $TransactionData + } finally { + # Make sure we free the unmanaged memory + [System.Runtime.InteropServices.Marshal]::FreeHGlobal($OutBuffer) + } +} + +Function Get-SnapshotPath { + <# + .SYNOPSIS + Get all VSS snapshot paths for the path specified. + + .DESCRIPTION + Scans the UNC or Local path for a list of VSS snapshots and the path that + can be used to reach these files. + + .PARAMETER Path + The UNC or Local path to search. The local path will be automatically + converted to \\localhost\$\ as the methods used inside this + function are only available for UNC paths. + + .EXAMPLE + Get-SnapshotPath -Path \\server\share + Get-SnapshotPath -Path C:\Windows + #> + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [System.String] + $Path + ) + + # Automatically convert a local path to a UNC path + if (-not ([Uri]$Path).IsUnc) { + $Qualifier = Split-Path -Path $Path -Qualifier + $UnqualifiedPath = Split-Path -Path $Path -NoQualifier + $Path = '\\localhost\{0}${1}' -f $Qualifier.Substring(0, 1), $UnqualifiedPath + } + + if (-not (Test-Path -LiteralPath $Path)) { + Write-Error -Message "Could not find UNC path '$Path'" -Category ObjectNotFound + return + } + + # Create a SafeFileHandle of the path specified and make sure it is valid + $Handle = [Win32.NativeMethods]::CreateFileW( + $Path, + [System.Security.AccessControl.FileSystemRights]"ListDirectory, ReadAttributes, Synchronize", + [System.IO.FileShare]::ReadWrite, + [System.IntPtr]::Zero, + [System.IO.FileMode]::Open, + 0x02000000, # FILE_FLAG_BACKUP_SEMANTICS + [System.IntPtr]::Zero + ) + if ($Handle.IsInvalid) { + $LastError = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() + $Msg = Get-LastWin32ExceptionMessage -ErrorCode $LastError + Write-Error -Message "CreateFileW($Path) failed - $Msg" + return + } + + try { + # Set the initial buffer size to the size of NT_Trans_Data + 2 chars. We do this so we can get the actual buffer + # size that is contained in the NT_Trans_Data struct. A char is 2 bytes (UTF-16) and we expect 2 of them + $TransDataSize = [System.Runtime.InteropServices.Marshal]::SizeOf([Type][Win32.NativeHelpers+NT_Trans_Data]) + $BufferSize = $TransDataSize + 4 + + # Invoke NtFsControlFile at least once to get the number of snapshots and total size of the NT_Trans_Data + # buffer. If there are 1 or more snapshots we invoke it again to get the actual snapshot strings + Invoke-EnumerateSnapshots -Handle $Handle -BufferSize $BufferSize -ScriptBlock { + $TransactionData = $args[1] + + if ($TransactionData.NumberOfSnapShots -gt 0) { + # There are snapshots to retrieve, reset the buffer size to the original size + the return array size + $NewBufferSize = $BufferSize + $TransactionData.SnapShotArraySize + + # Invoke NtFsControlFile with the larger buffer size but now we can parse the NT_Trans_Data + Invoke-EnumerateSnapshots -Handle $Handle -BufferSize $NewBufferSize -ScriptBlock { + $OutBuffer = $args[0] + $TransactionData = $args[1] + + $SnapshotPtr = [System.IntPtr]::Add($OutBuffer, $TransDataSize) + $SnapshotString = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($SnapshotPtr, + $TransactionData.SnapShotArraySize / 2) + + Write-Output -InputObject ($SnapshotString.Split([char[]]@("`0"), [System.StringSplitOptions]::RemoveEmptyEntries)) + } + } + } | ForEach-Object -Process { Join-Path -Path $Path -ChildPath $_ } + } finally { + # Technically not needed as a SafeFileHandle will auto dispose once the GC is called but it's good to be + # explicit about these things + $Handle.Dispose() + } +} + +Export-ModuleMember -Function Get-SnapshotPath diff --git a/_posts/2019-04-30-VSS-from-server-share.md b/_posts/2019-04-30-VSS-from-server-share.md new file mode 100644 index 0000000000000..7a7eca5b9824b --- /dev/null +++ b/_posts/2019-04-30-VSS-from-server-share.md @@ -0,0 +1,36 @@ +--- +layout: post +title: PowerShell - access Volume Shadow Copy (Previous Versions) of a network share +date: 2019-04-30 +tags: [PowerShell,Other] +--- + +Jordan Borean has come up with a way to get to +"Previous Versions" of network shares using Powershell! + +[Here is the relevant Reddit comment](https://www.reddit.com/r/PowerShell/comments/b2wenl/using_deviceiocontrol_and_fsctl_srv_enumerate/eiy0j03/), +and it links to [their module code on GitHub](https://gist.github.com/jborean93/f60da33b08f8e1d5e0ef545b0a4698a0) + +Example usage: + +```powershell +# Annoying issue with older .NET versions, you need to explicitly enable TLS 1.2 for TLS 1.2 only sites +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +Invoke-WebRequest -Uri "https://gist.githubusercontent.com/jborean93/f60da33b08f8e1d5e0ef545b0a4698a0/raw/7657ad8e24c595db8ad563cc6dbc434c2bbc01f6/Get-SnapshotPath.psm1" -OutFile Get-SnapshotPath.psm1 +Import-Module -Name .\Get-SnapshotPath.psm1 +Get-SnapshotPath -Path "\\dc01\c$" +Get-SnapshotPath -Path "\\dc01\c$\Windows" +``` + +If you use Powershell alone, +it won't find any previous version files, you can't get to them. +You need to use Windows Explorer first so it can send the right control codes to the server. +This code works out what Explorer is sending to the server and mimics that. +That's why it's cool! + + +You can then use the `\\SERVER\SHARE\@GMT-XXXX.XX.XX-XX.XX.XX` format of VSS file paths, +and use `Copy-Item` to recover files, etc. + +[Link to copy of source, in case github Gist is removed](static-files/2019-04-30-Get-SnapshotPath.psm1.txt) + From 81425539d7afc0599a4f0e9a538ab6c1b7eb5103 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Wed, 1 May 2019 10:15:00 +0100 Subject: [PATCH 44/48] fix relative link path --- _posts/2019-04-30-VSS-from-server-share.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2019-04-30-VSS-from-server-share.md b/_posts/2019-04-30-VSS-from-server-share.md index 7a7eca5b9824b..6b2c644277b65 100644 --- a/_posts/2019-04-30-VSS-from-server-share.md +++ b/_posts/2019-04-30-VSS-from-server-share.md @@ -32,5 +32,5 @@ That's why it's cool! You can then use the `\\SERVER\SHARE\@GMT-XXXX.XX.XX-XX.XX.XX` format of VSS file paths, and use `Copy-Item` to recover files, etc. -[Link to copy of source, in case github Gist is removed](static-files/2019-04-30-Get-SnapshotPath.psm1.txt) +[Link to copy of source, in case github Gist is removed](/static-files/2019-04-30-Get-SnapshotPath.psm1.txt) From 15b4fd45aa55119f627e980153b3ba69626e22a6 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Wed, 1 May 2019 11:27:46 +0100 Subject: [PATCH 45/48] . --- _includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt b/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt index 2df4187de66ee..44f01740618d2 100644 --- a/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt +++ b/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt @@ -1,4 +1,4 @@ -# Cloned from https://gist.github.com/jborean93/f60da33b08f8e1d5e0ef545b0a4698a0 +# Copied from https://gist.github.com/jborean93/f60da33b08f8e1d5e0ef545b0a4698a0 # Copyright: (c) 2019, Jordan Borean (@jborean93) # MIT License (see LICENSE or https://opensource.org/licenses/MIT) From c850ef87f0c5d79239f940e5791e8f44c6b2da2f Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Wed, 1 May 2019 11:29:13 +0100 Subject: [PATCH 46/48] move static-files folder to right place --- .../2019-04-30-Get-SnapshotPath.psm1.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {_includes/static-files => static-files}/2019-04-30-Get-SnapshotPath.psm1.txt (100%) diff --git a/_includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt b/static-files/2019-04-30-Get-SnapshotPath.psm1.txt similarity index 100% rename from _includes/static-files/2019-04-30-Get-SnapshotPath.psm1.txt rename to static-files/2019-04-30-Get-SnapshotPath.psm1.txt From 200338da33cd043c1db0251c30b844d88d3ad655 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Thu, 9 May 2019 13:26:24 +0100 Subject: [PATCH 47/48] work in progress on APL/Euler blog posts --- _posts/2019-10-20-APL-01-Project-Euler-1.md | 129 ++++ ...-01-Fifty-Perl-One-Liners-In-PowerShell.md | 21 + static-files/perl1line.txt | 613 ++++++++++++++++++ 3 files changed, 763 insertions(+) create mode 100644 _posts/2019-10-20-APL-01-Project-Euler-1.md create mode 100644 _posts/_postholder/2019-05-01-Fifty-Perl-One-Liners-In-PowerShell.md create mode 100644 static-files/perl1line.txt diff --git a/_posts/2019-10-20-APL-01-Project-Euler-1.md b/_posts/2019-10-20-APL-01-Project-Euler-1.md new file mode 100644 index 0000000000000..4e69fd2c7c37e --- /dev/null +++ b/_posts/2019-10-20-APL-01-Project-Euler-1.md @@ -0,0 +1,129 @@ +--- +layout: post +title: APL - Project Euler 1 +date: 2019-05-09 +tags: [APL] +--- + +Many APL/J/K comments on the internet are "*here's my unreadable one-liner /splat/*", +and it might be nice if people shared more of their thought processes. +Ideally experts would do it, but I'm a novice and I can only write my point of view. +I'm playing with the free NARS2000 version +([download here](http://www.nars2000.org/download/Download.html)). + +The [first Project Euler problem](https://projecteuler.net/problem=1) is similar to FizzBuzz, +it asks: + +---- + +> If we list all the natural numbers below 10 that are multiples of 3 or 5, +we get 3, 5, 6 and 9. The sum of these multiples is 23. +> +> Find the sum of all the multiples of 3 or 5 below 1000. + +We need ten numbers, "integers to ten" is *iota ten* + +```APL + ⍳10 +1 2 3 4 5 6 7 8 9 10 +``` + +and we need "divide by three, check if the remainder is zero". +APL uses the pipe for remainder, +```APL + + ⍝ 3|8 says "remainder after three goes into eight", answer is two. + 3|8 +2 + ⍝ 3|⍳10 says the same, but remainders for three into all the integers to ten. + 3|⍳10 +1 2 0 1 2 0 1 2 0 1 + ⍝ 0=3|⍳10 asks where the remainder is zero, APL executes right to left; + ⍝ see that the ones line up with three, six, nine, or the multiples of three. + ⍝ and see the same pattern lines up multiples of five afterwards. + 0=3|⍳10 +0 0 1 0 0 1 0 0 1 0 + ⍳10 +1 2 3 4 5 6 7 8 9 10 + 0=5|⍳10 +0 0 0 0 1 0 0 0 0 1 +``` + +This idea of an array of zeros and ones which line up with +the elements of another array by their position, +is quite important and quite useful. + +We'll use a boolean OR to combine the arrays of zero and one, +any position with a one in either array stays as a one kept. + +Then we use the `/` function which is "replicate". +It takes a control array of numbers on the left, +data on the right, and repeats each data item as many times +as the control number in the same position, says to. +`0 0 1 0 2/1 2 3 4 5` gives `3 5 5` + +It's often used with zeros and ones to filter and drop, +zero meaning "replicate it no times" and one indicating "keep it". + +```APL + ⍝ Indicates multiples of three and multiples of five. + (0=5|⍳10) ∨ (0=3|⍳10) +0 0 1 0 1 1 0 0 1 1 + ⍝ pick out multiples of three or five from the integers to ten. + ((0=5|⍳10) ∨ (0=3|⍳10)) / ⍳10 +3 5 6 9 10 + ⍝ Use the / operator which looks the same but is different, to sum them up + ⍝ plus over the multiples of three and five in the integers to ten: + +/ ((0=5|⍳10) ∨ (0=3|⍳10)) / ⍳10 +33 +``` + +and we have our test answer 23. + +Oops, we have ten more than the desired answer, +because the question says "numbers below ten", not "numbers to ten"; +make the "integers to ten" into "integers to nine": + +```APL + +/ ((0=5|⍳9) ∨ (0=3|⍳9)) / ⍳9 +23 +``` + +[Try it on TryAPL.org](https://tryapl.org/?a=+/%20%28%280%3D5%7C%u23739%29%20%u2228%20%280%3D3%7C%u23739%29%29%20/%20%u23739&run) + +Let's just split out the integers to nine into N, +to get rid of that repetition: + +```APL + N ← ⍳9 + +/ ((0=5|N) ∨ (0=3|N)) / N +23 +``` + +Great, now I've introduced the basic patterns, I can start the blog post ;) + +Can we get rid of the repeated code, +get the remainder of three and five in one operation? +Yes, with "all combinations of things on the left and things on the right" +called an outer product: + +```APL + ⍝ Get all combinations of three and five on the left, + ⍝ integers to nine on the right, and combining with + ⍝ remainder, to get two rows of output: + N ← ⍳9 + 0=3 5 ∘.| N +0 0 1 0 0 1 0 0 1 +0 0 0 0 1 0 0 0 0 + ⍝ combine with the OR operation down the columns with ⌿ + ⍝ to get the same combinations we had earlier + ∨ ⌿ (0=3 5 ∘.| N) +0 0 1 0 1 1 0 0 1 + ⍝ replicate over N to pick out the multiples + (∨ ⌿ 0=3 5 ∘.| N) / N +3 5 6 9 + ⍝ plus over those, to sum them up + + / (∨ ⌿ 0=3 5 ∘.| N) / N +23 +``` + diff --git a/_posts/_postholder/2019-05-01-Fifty-Perl-One-Liners-In-PowerShell.md b/_posts/_postholder/2019-05-01-Fifty-Perl-One-Liners-In-PowerShell.md new file mode 100644 index 0000000000000..e76f79be54d75 --- /dev/null +++ b/_posts/_postholder/2019-05-01-Fifty-Perl-One-Liners-In-PowerShell.md @@ -0,0 +1,21 @@ +--- +layout: post +title: 50 Perl one-liners in PowerShell +date: 2019-05-01 +tags: [PowerShell,Perl] +--- + +Peter Krumins has [a collection of "Fifty Perl 1Liners"](https://catonmat.net/ftp/perl1line.txt) +and I've been wondering how many of them would translate to PowerShell, +and how nicely they would translate. + +The table of contents is: + + 1. File Spacing + 2. Line Numbering + 3. Calculations + 4. String Creation and Array Creation + 5. Text Conversion and Substitution + 6. Selective Printing and Deleting of Certain Lines + 7. Handy Regular Expressions + 8. Perl tricks diff --git a/static-files/perl1line.txt b/static-files/perl1line.txt new file mode 100644 index 0000000000000..2e4ea9ad986d3 --- /dev/null +++ b/static-files/perl1line.txt @@ -0,0 +1,613 @@ +Useful One-Line Scripts for Perl Jan 27 2019 | version 1.12 +-------------------------------- ----------- ------------ + +Compiled by Peter Krumins (peter@catonmat.net, @pkrumins on twitter) +https://www.catonmat.net -- good coders code, great coders reuse + +Latest version of this file is always at: + + https://catonmat.net/ftp/perl1line.txt + +This file is also available in other languages: + + Chinese: https://github.com/vinian/perl1line.txt + + Please email me peter@catonmat.net if you want to translate it. + +Perl One-Liners on Github: + + https://github.com/pkrumins/perl1line.txt + + You can send me pull requests over GitHub! I accept bug fixes, + new one-liners, translations and everything else related. + +I have also written "Perl One-Liners Explained" ebook that's based on +this file. It explains all the one-liners here. Get it at: + + https://catonmat.net/perl-book + +No Starch Press has published "Perl One-Liners" as a real book too: + + https://nostarch.com/perloneliners + +These one-liners work both on UNIX systems and Windows. Most likely your +UNIX system already has Perl. For Windows get the Strawberry Perl at: + + http://www.strawberryperl.com + +Table of contents: + + 1. File Spacing + 2. Line Numbering + 3. Calculations + 4. String Creation and Array Creation + 5. Text Conversion and Substitution + 6. Selective Printing and Deleting of Certain Lines + 7. Handy Regular Expressions + 8. Perl tricks + + +FILE SPACING +------------ + +# Double space a file +perl -pe '$\="\n"' +perl -pe 'BEGIN { $\="\n" }' +perl -pe '$_ .= "\n"' +perl -pe 's/$/\n/' +perl -nE 'say' + +# Double space a file, except the blank lines +perl -pe '$_ .= "\n" unless /^$/' +perl -pe '$_ .= "\n" if /\S/' + +# Triple space a file +perl -pe '$\="\n\n"' +perl -pe '$_.="\n\n"' + +# N-space a file +perl -pe '$_.="\n"x7' + +# Add a blank line before every line +perl -pe 's//\n/' + +# Remove all blank lines +perl -ne 'print unless /^$/' +perl -lne 'print if length' +perl -ne 'print if /\S/' + +# Remove all consecutive blank lines, leaving just one +perl -00 -pe '' +perl -00pe0 + +# Compress/expand all blank lines into N consecutive ones +perl -00 -pe '$_.="\n"x4' + +# Fold a file so that every set of 10 lines becomes one tab-separated line +perl -lpe '$\ = $. % 10 ? "\t" : "\n"' + + +LINE NUMBERING +-------------- + +# Number all lines in a file +perl -pe '$_ = "$. $_"' + +# Number only non-empty lines in a file +perl -pe '$_ = ++$a." $_" if /./' + +# Number and print only non-empty lines in a file (drop empty lines) +perl -ne 'print ++$a." $_" if /./' + +# Number all lines but print line numbers only non-empty lines +perl -pe '$_ = "$. $_" if /./' + +# Number only lines that match a pattern, print others unmodified +perl -pe '$_ = ++$a." $_" if /regex/' + +# Number and print only lines that match a pattern +perl -ne 'print ++$a." $_" if /regex/' + +# Number all lines, but print line numbers only for lines that match a pattern +perl -pe '$_ = "$. $_" if /regex/' + +# Number all lines in a file using a custom format (emulate cat -n) +perl -ne 'printf "%-5d %s", $., $_' + +# Print the total number of lines in a file (emulate wc -l) +perl -lne 'END { print $. }' +perl -le 'print $n=()=<>' +perl -le 'print scalar(()=<>)' +perl -le 'print scalar(@foo=<>)' +perl -ne '}{print $.' +perl -nE '}{say $.' + +# Print the number of non-empty lines in a file +perl -le 'print scalar(grep{/./}<>)' +perl -le 'print ~~grep{/./}<>' +perl -le 'print~~grep/./,<>' +perl -E 'say~~grep/./,<>' + +# Print the number of empty lines in a file +perl -lne '$a++ if /^$/; END {print $a+0}' +perl -le 'print scalar(grep{/^$/}<>)' +perl -le 'print ~~grep{/^$/}<>' +perl -E 'say~~grep{/^$/}<>' + +# Print the number of lines in a file that match a pattern (emulate grep -c) +perl -lne '$a++ if /regex/; END {print $a+0}' +perl -nE '$a++ if /regex/; END {say $a+0}' + + +CALCULATIONS +------------ + +# Check if a number is a prime +perl -lne '(1x$_) !~ /^1?$|^(11+?)\1+$/ && print "$_ is prime"' + +# Print the sum of all the fields on a line +perl -MList::Util=sum -alne 'print sum @F' + +# Print the sum of all the fields on all lines +perl -MList::Util=sum -alne 'push @S,@F; END { print sum @S }' +perl -MList::Util=sum -alne '$s += sum @F; END { print $s }' + +# Shuffle all fields on a line +perl -MList::Util=shuffle -alne 'print "@{[shuffle @F]}"' +perl -MList::Util=shuffle -alne 'print join " ", shuffle @F' + +# Find the minimum element on a line +perl -MList::Util=min -alne 'print min @F' + +# Find the minimum element over all the lines +perl -MList::Util=min -alne '@M = (@M, @F); END { print min @M }' +perl -MList::Util=min -alne '$min = min @F; $rmin = $min unless defined $rmin && $min > $rmin; END { print $rmin }' + +# Find the maximum element on a line +perl -MList::Util=max -alne 'print max @F' + +# Find the maximum element over all the lines +perl -MList::Util=max -alne '@M = (@M, @F); END { print max @M }' + +# Replace each field with its absolute value +perl -alne 'print "@{[map { abs } @F]}"' + +# Find the total number of fields (words) on each line +perl -alne 'print scalar @F' + +# Print the total number of fields (words) on each line followed by the line +perl -alne 'print scalar @F, " $_"' + +# Find the total number of fields (words) on all lines +perl -alne '$t += @F; END { print $t}' + +# Print the total number of fields that match a pattern +perl -alne 'map { /regex/ && $t++ } @F; END { print $t }' +perl -alne '$t += /regex/ for @F; END { print $t }' +perl -alne '$t += grep /regex/, @F; END { print $t }' + +# Print the total number of lines that match a pattern +perl -lne '/regex/ && $t++; END { print $t }' + +# Print the number PI to n decimal places +perl -Mbignum=bpi -le 'print bpi(n)' + +# Print the number PI to 39 decimal places +perl -Mbignum=PI -le 'print PI' + +# Print the number E to n decimal places +perl -Mbignum=bexp -le 'print bexp(1,n+1)' + +# Print the number E to 39 decimal places +perl -Mbignum=e -le 'print e' + +# Print UNIX time (seconds since Jan 1, 1970, 00:00:00 UTC) +perl -le 'print time' + +# Print GMT (Greenwich Mean Time) and local computer time +perl -le 'print scalar gmtime' +perl -le 'print scalar localtime' + +# Print local computer time in H:M:S format +perl -le 'print join ":", (localtime)[2,1,0]' + +# Print yesterday's date +perl -MPOSIX -le '@now = localtime; $now[3] -= 1; print scalar localtime mktime @now' + +# Print date 14 months, 9 days and 7 seconds ago +perl -MPOSIX -le '@now = localtime; $now[0] -= 7; $now[4] -= 14; $now[7] -= 9; print scalar localtime mktime @now' + +# Prepend timestamps to stdout (GMT, localtime) +tail -f logfile | perl -ne 'print scalar gmtime," ",$_' +tail -f logfile | perl -ne 'print scalar localtime," ",$_' + +# Calculate factorial of 5 +perl -MMath::BigInt -le 'print Math::BigInt->new(5)->bfac()' +perl -le '$f = 1; $f *= $_ for 1..5; print $f' + +# Calculate greatest common divisor (GCM) +perl -MMath::BigInt=bgcd -le 'print bgcd(@list_of_numbers)' + +# Calculate GCM of numbers 20 and 35 using Euclid's algorithm +perl -le '$n = 20; $m = 35; ($m,$n) = ($n,$m%$n) while $n; print $m' + +# Calculate least common multiple (LCM) of numbers 35, 20 and 8 +perl -MMath::BigInt=blcm -le 'print blcm(35,20,8)' + +# Calculate LCM of 20 and 35 using Euclid's formula: n*m/gcd(n,m) +perl -le '$a = $n = 20; $b = $m = 35; ($m,$n) = ($n,$m%$n) while $n; print $a*$b/$m' + +# Generate 10 random numbers between 5 and 15 (excluding 15) +perl -le '$n=10; $min=5; $max=15; $, = " "; print map { int(rand($max-$min))+$min } 1..$n' + +# Find and print all permutations of a list +perl -MAlgorithm::Permute -le '$l = [1,2,3,4,5]; $p = Algorithm::Permute->new($l); print @r while @r = $p->next' + +# Generate the power set +perl -MList::PowerSet=powerset -le '@l = (1,2,3,4,5); for (@{powerset(@l)}) { print "@$_" }' + +# Convert an IP address to unsigned integer +perl -le '$i=3; $u += ($_<<8*$i--) for "127.0.0.1" =~ /(\d+)/g; print $u' +perl -le '$ip="127.0.0.1"; $ip =~ s/(\d+)\.?/sprintf("%02x", $1)/ge; print hex($ip)' +perl -le 'print unpack("N", 127.0.0.1)' +perl -MSocket -le 'print unpack("N", inet_aton("127.0.0.1"))' + +# Convert an unsigned integer to an IP address +perl -MSocket -le 'print inet_ntoa(pack("N", 2130706433))' +perl -le '$ip = 2130706433; print join ".", map { (($ip>>8*($_))&0xFF) } reverse 0..3' +perl -le '$ip = 2130706433; $, = "."; print map { (($ip>>8*($_))&0xFF) } reverse 0..3' + + +STRING CREATION AND ARRAY CREATION +---------------------------------- + +# Generate and print the alphabet +perl -le 'print a..z' +perl -le 'print ("a".."z")' +perl -le '$, = ","; print ("a".."z")' +perl -le 'print join ",", ("a".."z")' + +# Generate and print all the strings from "a" to "zz" +perl -le 'print ("a".."zz")' +perl -le 'print "aa".."zz"' + +# Create a hex lookup table +@hex = (0..9, "a".."f") + +# Convert a decimal number to hex using @hex lookup table +perl -le '$num = 255; @hex = (0..9, "a".."f"); while ($num) { $s = $hex[($num%16)&15].$s; $num = int $num/16 } print $s' +perl -le '$hex = sprintf("%x", 255); print $hex' +perl -le '$num = "ff"; print hex $num' + +# Generate a random 8 character password +perl -le 'print map { ("a".."z")[rand 26] } 1..8' +perl -le 'print map { ("a".."z", 0..9)[rand 36] } 1..8' + +# Create a string of specific length +perl -le 'print "a"x50' + +# Create a repeated list of elements +perl -le '@list = (1,2)x20; print "@list"' + +# Create an array from a string +@months = split ' ', "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec" +@months = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/ + +# Create a string from an array +@stuff = ("hello", 0..9, "world"); $string = join '-', @stuff + +# Find the numeric values for characters in the string +perl -le 'print join ", ", map { ord } split //, "hello world"' + +# Convert a list of numeric ASCII values into a string +perl -le '@ascii = (99, 111, 100, 105, 110, 103); print pack("C*", @ascii)' +perl -le '@ascii = (99, 111, 100, 105, 110, 103); print map { chr } @ascii' + +# Generate an array with odd numbers from 1 to 100 +perl -le '@odd = grep {$_ % 2 == 1} 1..100; print "@odd"' +perl -le '@odd = grep { $_ & 1 } 1..100; print "@odd"' + +# Generate an array with even numbers from 1 to 100 +perl -le '@even = grep {$_ % 2 == 0} 1..100; print "@even"' + +# Find the length of the string +perl -le 'print length "one-liners are great"' + +# Find the number of elements in an array +perl -le '@array = ("a".."z"); print scalar @array' +perl -le '@array = ("a".."z"); print $#array + 1' + + +TEXT CONVERSION AND SUBSTITUTION +-------------------------------- + +# ROT13 a string +'y/A-Za-z/N-ZA-Mn-za-m/' + +# ROT 13 a file +perl -lpe 'y/A-Za-z/N-ZA-Mn-za-m/' file + +# Base64 encode a string +perl -MMIME::Base64 -e 'print encode_base64("string")' +perl -MMIME::Base64 -0777 -ne 'print encode_base64($_)' file + +# Base64 decode a string +perl -MMIME::Base64 -le 'print decode_base64("base64string")' +perl -MMIME::Base64 -ne 'print decode_base64($_)' file + +# URL-escape a string +perl -MURI::Escape -le 'print uri_escape($string)' + +# URL-unescape a string +perl -MURI::Escape -le 'print uri_unescape($string)' + +# HTML-encode a string +perl -MHTML::Entities -le 'print encode_entities($string)' + +# HTML-decode a string +perl -MHTML::Entities -le 'print decode_entities($string)' + +# Convert all text to uppercase +perl -nle 'print uc' +perl -ple '$_=uc' +perl -nle 'print "\U$_"' + +# Convert all text to lowercase +perl -nle 'print lc' +perl -ple '$_=lc' +perl -nle 'print "\L$_"' + +# Uppercase only the first word of each line +perl -nle 'print ucfirst lc' +perl -nle 'print "\u\L$_"' + +# Invert the letter case +perl -ple 'y/A-Za-z/a-zA-Z/' + +# Camel case each line +perl -ple 's/(\w+)/\u$1/g' +perl -ple 's/(?= 80' + +# Print lines that are less than 80 chars in length +perl -ne 'print if length < 80' + +# Print only line 13 +perl -ne '$. == 13 && print && exit' + +# Print all lines except line 27 +perl -ne '$. != 27 && print' +perl -ne 'print if $. != 27' + +# Print only lines 13, 19 and 67 +perl -ne 'print if $. == 13 || $. == 19 || $. == 67' +perl -ne 'print if int($.) ~~ (13, 19, 67)' + +# Print all lines between two regexes (including lines that match regex) +perl -ne 'print if /regex1/../regex2/' + +# Print all lines from line 17 to line 30 +perl -ne 'print if $. >= 17 && $. <= 30' +perl -ne 'print if int($.) ~~ (17..30)' +perl -ne 'print if grep { $_ == $. } 17..30' + +# Print the longest line +perl -ne '$l = $_ if length($_) > length($l); END { print $l }' + +# Print the shortest line +perl -ne '$s = $_ if $. == 1; $s = $_ if length($_) < length($s); END { print $s }' + +# Print all lines that contain a number +perl -ne 'print if /\d/' + +# Find all lines that contain only a number +perl -ne 'print if /^\d+$/' + +# Print all lines that contain only characters +perl -ne 'print if /^[[:alpha:]]+$/' + +# Print every second line +perl -ne 'print if $. % 2' + +# Print every second line, starting the second line +perl -ne 'print if $. % 2 == 0' + +# Print all lines that repeat +perl -ne 'print if ++$a{$_} == 2' + +# Print all unique lines +perl -ne 'print unless $a{$_}++' + +# Print the first field (word) of every line (emulate cut -f 1 -d ' ') +perl -alne 'print $F[0]' + + +HANDY REGULAR EXPRESSIONS +------------------------- + +# Match something that looks like an IP address +/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ +/^(\d{1,3}\.){3}\d{1,3}$/ + +# Test if a number is in range 0-255 +/^([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$/ + +# Match an IP address +my $ip_part = qr|([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|; +if ($ip =~ /^($ip_part\.){3}$ip_part$/) { + say "valid ip"; +} + +# Check if the string looks like an email address +/\S+@\S+\.\S+/ + +# Check if the string is a decimal number +/^\d+$/ +/^[+-]?\d+$/ +/^[+-]?\d+\.?\d*$/ + +# Check if the string is a hexadecimal number +/^0x[0-9a-f]+$/i + +# Check if the string is an octal number +/^0[0-7]+$/ + +# Check if the string is binary +/^[01]+$/ + +# Check if a word appears twice in the string +/(word).*\1/ + +# Increase all numbers by one in the string +$str =~ s/(\d+)/$1+1/ge + +# Extract HTTP User-Agent string from the HTTP headers +/^User-Agent: (.+)$/ + +# Match printable ASCII characters +/[ -~]/ + +# Match unprintable ASCII characters +/[^ -~]/ + +# Match text between two HTML tags +m|([^<]*)| +m|(.*?)| + +# Replace all tags with +$html =~ s|<(/)?b>|<$1strong>|g + +# Extract all matches from a regular expression +my @matches = $text =~ /regex/g; + + +PERL TRICKS +----------- + +# Print the version of a Perl module +perl -MModule -le 'print $Module::VERSION' +perl -MLWP::UserAgent -le 'print $LWP::UserAgent::VERSION' + + +PERL ONE-LINERS EXPLAINED E-BOOK +-------------------------------- + +I have written an ebook based on the one-liners in this file. If you want to +support my work and learn more about these one-liners, you can get a copy +of my ebook at: + + https://catonmat.net/perl-book + +The ebook is based on the 7-part article series that I wrote on my blog. +In the ebook I reviewed all the one-liners, improved explanations, added +new ones, and added two new chapters - introduction to Perl one-liners +and summary of commonly used special variables. + +You can read the original article series here: + + https://catonmat.net/perl-one-liners-explained-part-one + https://catonmat.net/perl-one-liners-explained-part-two + https://catonmat.net/perl-one-liners-explained-part-three + https://catonmat.net/perl-one-liners-explained-part-four + https://catonmat.net/perl-one-liners-explained-part-five + https://catonmat.net/perl-one-liners-explained-part-six + https://catonmat.net/perl-one-liners-explained-part-seven + + +CREDITS +------- + +Andy Lester http://www.petdance.com +Shlomi Fish http://www.shlomifish.org +Madars Virza http://www.madars.org +caffecaldo https://github.com/caffecaldo +Kirk Kimmel https://github.com/kimmel +avar https://github.com/avar +rent0n + + +FOUND A BUG? HAVE ANOTHER ONE-LINER? +------------------------------------ + +Email bugs and new one-liners to me at peter@catonmat.net. + + +HAVE FUN +-------- + +I hope you found these one-liners useful. Have fun and see ya! + +#---end of file--- From b5ec888fb4a0aa62fa1c8a79ff750ca14b74da58 Mon Sep 17 00:00:00 2001 From: HumanEquivalentUnit Date: Sun, 19 May 2019 23:36:44 +0100 Subject: [PATCH 48/48] edit of APL/Euler 1 blog --- _posts/2019-05-19-APL-01-Project-Euler-1.md | 258 ++++++++++++++++++++ _posts/2019-10-20-APL-01-Project-Euler-1.md | 129 ---------- static-files/Apl385.ttf | Bin 0 -> 212256 bytes 3 files changed, 258 insertions(+), 129 deletions(-) create mode 100644 _posts/2019-05-19-APL-01-Project-Euler-1.md delete mode 100644 _posts/2019-10-20-APL-01-Project-Euler-1.md create mode 100644 static-files/Apl385.ttf diff --git a/_posts/2019-05-19-APL-01-Project-Euler-1.md b/_posts/2019-05-19-APL-01-Project-Euler-1.md new file mode 100644 index 0000000000000..a79c1b4fe1ff9 --- /dev/null +++ b/_posts/2019-05-19-APL-01-Project-Euler-1.md @@ -0,0 +1,258 @@ +--- +layout: post +title: APL - Project Euler 1 +date: 2019-05-09 +tags: [APL] +--- + +Many APL/J/K comments on the internet are "*here's my unreadable one-liner /splat/*", +and it might be nice if people shared more of their thought processes. +Ideally experts would do it, but I'm a novice and I can only write my point of view. +I'm playing with the free NARS2000 version +([download here](http://www.nars2000.org/download/Download.html)). + +The [first Project Euler problem](https://projecteuler.net/problem=1) is similar to FizzBuzz, +it asks: + +---- + +> If we list all the natural numbers below 10 that are multiples of 3 or 5, +we get 3, 5, 6 and 9. The sum of these multiples is 23. +> +> Find the sum of all the multiples of 3 or 5 below 1000. + +We need ten numbers, "integers to ten" is *iota ten* + +```APL + ⍳10 +1 2 3 4 5 6 7 8 9 10 +``` + +and we need "divide by three, check if the remainder is zero". +APL uses the pipe for remainder, it looks like this: + +```APL + + ⍝ 3|8 says "remainder after three goes into eight", answer is two. + 3|8 +2 + ⍝ 3|⍳10 says the same, but remainders for three into all the integers to ten. + 3|⍳10 +1 2 0 1 2 0 1 2 0 1 + ⍝ 0=3|⍳10 asks where the remainder is zero, APL executes right to left; + ⍝ see that the ones line up with three, six, nine, or the multiples of three. + ⍝ and see the same pattern lines up multiples of five afterwards. + 0=3|⍳10 +0 0 1 0 0 1 0 0 1 0 + ⍳10 +1 2 3 4 5 6 7 8 9 10 + 0=5|⍳10 +0 0 0 0 1 0 0 0 0 1 +``` + +This idea of an array of zeros and ones which line up with +the elements of another array by their position, +is often used in APL. + +We'll use a boolean OR `∨` to combine the arrays of zero and one, +any position with a one in either array stays as a one kept. + +```APL + ⍝ Indicates multiples of three and multiples of five. + (0=5|⍳10) ∨ (0=3|⍳10) +0 0 1 0 1 1 0 0 1 1 +``` + +Then we use the `/` function which is "replicate". +It takes a control array of numbers on the left, +a data array on the right, and repeats each data item as many times +as the control number says to. Matching them up by position, e.g. +`0 0 1 0 2/1 2 3 4 5` gives `3 5 5`. + +It's often used with zeros and ones to act as a filter, +zero meaning "replicate it no times (drop it)" and one indicating "keep it". + +```APL + ⍝ pick out multiples of three or five from the integers to ten. + ((0=5|⍳10) ∨ (0=3|⍳10)) / ⍳10 +3 5 6 9 10 + ⍝ Use the / operator (which looks the same as the / function) to sum them up. + ⍝ plus over the multiples of three and five, in the integers to ten: + +/ ((0=5|⍳10) ∨ (0=3|⍳10)) / ⍳10 +33 +``` + +and we have our test answer 23. + +Oops, we have ten more than the desired answer, +because the question says "numbers below ten", not "numbers to ten"; +let's make the "integers to ten" into "integers to nine": + +```APL + +/ ((0=5|⍳9) ∨ (0=3|⍳9)) / ⍳9 +23 +``` + +Now we have the test answer. [Try it on TryAPL.org](https://tryapl.org/?a=+/%20%28%280%3D5%7C%u23739%29%20%u2228%20%280%3D3%7C%u23739%29%29%20/%20%u23739&run) + +Let's split out the integers to nine into a variable named N, +to get rid of that repetition: + +```APL + N ← ⍳9 + +/ ((0=5|N) ∨ (0=3|N)) / N +23 +``` + +Great, now I've introduced the basic patterns, +we can answer the prompt by changing N to the first 999 numbers, +and now I can start the blog post :) + +---- + +Can we get rid of the repeated code, +get the remainder of three and five in one operation? +Yes, using "all possible combinations of things on the left, and things on the right", +called an outer product, to give one array with the multiples of three and five in it, +on separate rows: + +```APL + ⍝ Get all combinations of three and five on the left, + ⍝ integers to nine on the right, and combining with + ⍝ the remainder operation, to get two rows of output: + N ← ⍳9 + 0=3 5 ∘.| N +0 0 1 0 0 1 0 0 1 +0 0 0 0 1 0 0 0 0 + ⍝ combine with the OR operation down the columns with ⌿ + ⍝ to get the same combinations we had earlier + ∨ ⌿ (0=3 5 ∘.| N) +0 0 1 0 1 1 0 0 1 + ⍝ replicate over N to pick out the multiples + (∨ ⌿ 0=3 5 ∘.| N) / N +3 5 6 9 + ⍝ plus over those, to sum them up + + / (∨ ⌿ 0=3 5 ∘.| N) / N +23 +``` + +Next, I upped N until it started to take a decently measurable time, +in this case six nines, integers to 999999. +The first one runs in 275-300ms. + +The second one, with less duplication, runs in 390ms. +I'm surprised, I thought keeping things to one array would be faster. +My novice guess is that it's because APL keeps data in row-major order, +meaning that in memory rows go 1111122222 so running along a row is fast, +the second approach to merge down "columns" is a lot more jumping around. + +What if we go the other way about this, +instead of using division and remainder we could multiply by 3 and 5, +then sum up the results. + +```APL + ⍝ three times integers to nine, and five times them + 3×⍳9 +3 6 9 12 15 18 21 24 27 + 5×⍳9 +5 10 15 20 25 30 35 40 45 + ⍝ multiples of three and five, catenated into one array + (3×⍳9), 5×⍳9 +3 6 9 12 15 18 21 24 27 5 10 15 20 25 30 35 40 45 + + ⍝ But they go way above 9, so we need to filter them + N←⍳9 + nums←(3×N), (5×N) + (9≥nums)/nums +3 6 9 5 +``` + +Same result, which is good. Now we can increase N, +but if we do, we get the wrong answer. +Because multiples of three gets fifteen and multiples of five does too. +Let's use `∪` for unique, to remove duplicates: + +``` + ⍝ Integers to 999, multiplied by three and five, + ⍝ filtered to remove any above 999, and summed up. + N←⍳999 + nums← ∪ (3×N), (5×N) + +/ (999≥nums)/nums +233168 +``` + +This works, but increasing it to 999999 for testing, +and it runs in 1.3 seconds. Not better. +Let's see if we can avoid generating the high numbers and throwing them away. + +Instead of making all the multiples of three and five, +we can divide the cutoff by three, +and know that multiplying by three won't go beyond the cutoff. + +```APL + ⍝ How many multiples of three, won't take us past 19? + 19 ÷ 3 +6.333333333 + ⍝ Integers to "one third of nineteen" is.. + ⍳ 19 ÷ 3 +DOMAIN ERROR + ⍝ oops, gotta round down here to use a whole number + ⍳ ⌊ 19 ÷ 3 +1 2 3 4 5 6 + ⍝ now multiply by three, show they don't go over nineteen + ⍝ multiples of three, to nineteen + 3 × ⍳ ⌊ 19 ÷ 3 +3 6 9 12 15 18 + + ⍝ same with five, join the two together + (3 × ⍳ ⌊ 19 ÷ 3) , (5 × ⍳ ⌊ 19 ÷ 5) +3 6 9 12 15 18 5 10 15 + + ⍝ move N out into a variable of the cutoff integer, + ⍝ not numbers up to a cutoff + ⍝ and remove duplicates, and sum them + N ← 999999 + +/ ∪ (3 × ⍳ ⌊ N ÷ 3) , (5 × ⍳ ⌊ N ÷ 5) +233333166668 +``` + +This runs in 300ms, which is nice. Best yet. + +Instead of making duplicates and removing them, +I trial-and-error tested moving `∪` into the middle, +turns out this makes "unique" do set union instead, +which joins the two without duplicates in the first place, +instead of joining them with duplicates and later removing them. + +```APL + N←999999 + +/ (3 × ⍳ ⌊ N ÷ 3) ∪ (5 × ⍳ ⌊ N ÷ 5) +233333166668 +``` + +This runs in 50ms. Way better! +I was pretty happy here, +and browsing the Project Euler forums where people share their solutions, +there were several in languages I couldn't read, +and I wished people had added some explanation. +That's where this blog post comes from. +There were a few which added up the multiples of three and five, +then subtracted the multiples of fifteen - a good idea. + +That looks like this + +```APL + N←999999 + (+/ 3 × ⍳ ⌊ N ÷ 3) + (+/ 5 × ⍳ ⌊ N ÷ 5) - (+/ 15 × ⍳ ⌊ N ÷ 15) +233333166668 +``` + +and THAT runs in 2ms. +Less, I think; NARS2000 doesn't seem to make much distinction below 2ms. +I can keep increasing the value of N here and it keeps saying 2ms, +until ninety nine thousand trillion where it can't run. + +Hopefully, that's a few approaches to a simple question explained, +and more evidence that "doing less work" is faster - +but it's not obvious to me from a traditional programming language background, +what code results in "less work" in APL. \ No newline at end of file diff --git a/_posts/2019-10-20-APL-01-Project-Euler-1.md b/_posts/2019-10-20-APL-01-Project-Euler-1.md deleted file mode 100644 index 4e69fd2c7c37e..0000000000000 --- a/_posts/2019-10-20-APL-01-Project-Euler-1.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -layout: post -title: APL - Project Euler 1 -date: 2019-05-09 -tags: [APL] ---- - -Many APL/J/K comments on the internet are "*here's my unreadable one-liner /splat/*", -and it might be nice if people shared more of their thought processes. -Ideally experts would do it, but I'm a novice and I can only write my point of view. -I'm playing with the free NARS2000 version -([download here](http://www.nars2000.org/download/Download.html)). - -The [first Project Euler problem](https://projecteuler.net/problem=1) is similar to FizzBuzz, -it asks: - ----- - -> If we list all the natural numbers below 10 that are multiples of 3 or 5, -we get 3, 5, 6 and 9. The sum of these multiples is 23. -> -> Find the sum of all the multiples of 3 or 5 below 1000. - -We need ten numbers, "integers to ten" is *iota ten* - -```APL - ⍳10 -1 2 3 4 5 6 7 8 9 10 -``` - -and we need "divide by three, check if the remainder is zero". -APL uses the pipe for remainder, -```APL - - ⍝ 3|8 says "remainder after three goes into eight", answer is two. - 3|8 -2 - ⍝ 3|⍳10 says the same, but remainders for three into all the integers to ten. - 3|⍳10 -1 2 0 1 2 0 1 2 0 1 - ⍝ 0=3|⍳10 asks where the remainder is zero, APL executes right to left; - ⍝ see that the ones line up with three, six, nine, or the multiples of three. - ⍝ and see the same pattern lines up multiples of five afterwards. - 0=3|⍳10 -0 0 1 0 0 1 0 0 1 0 - ⍳10 -1 2 3 4 5 6 7 8 9 10 - 0=5|⍳10 -0 0 0 0 1 0 0 0 0 1 -``` - -This idea of an array of zeros and ones which line up with -the elements of another array by their position, -is quite important and quite useful. - -We'll use a boolean OR to combine the arrays of zero and one, -any position with a one in either array stays as a one kept. - -Then we use the `/` function which is "replicate". -It takes a control array of numbers on the left, -data on the right, and repeats each data item as many times -as the control number in the same position, says to. -`0 0 1 0 2/1 2 3 4 5` gives `3 5 5` - -It's often used with zeros and ones to filter and drop, -zero meaning "replicate it no times" and one indicating "keep it". - -```APL - ⍝ Indicates multiples of three and multiples of five. - (0=5|⍳10) ∨ (0=3|⍳10) -0 0 1 0 1 1 0 0 1 1 - ⍝ pick out multiples of three or five from the integers to ten. - ((0=5|⍳10) ∨ (0=3|⍳10)) / ⍳10 -3 5 6 9 10 - ⍝ Use the / operator which looks the same but is different, to sum them up - ⍝ plus over the multiples of three and five in the integers to ten: - +/ ((0=5|⍳10) ∨ (0=3|⍳10)) / ⍳10 -33 -``` - -and we have our test answer 23. - -Oops, we have ten more than the desired answer, -because the question says "numbers below ten", not "numbers to ten"; -make the "integers to ten" into "integers to nine": - -```APL - +/ ((0=5|⍳9) ∨ (0=3|⍳9)) / ⍳9 -23 -``` - -[Try it on TryAPL.org](https://tryapl.org/?a=+/%20%28%280%3D5%7C%u23739%29%20%u2228%20%280%3D3%7C%u23739%29%29%20/%20%u23739&run) - -Let's just split out the integers to nine into N, -to get rid of that repetition: - -```APL - N ← ⍳9 - +/ ((0=5|N) ∨ (0=3|N)) / N -23 -``` - -Great, now I've introduced the basic patterns, I can start the blog post ;) - -Can we get rid of the repeated code, -get the remainder of three and five in one operation? -Yes, with "all combinations of things on the left and things on the right" -called an outer product: - -```APL - ⍝ Get all combinations of three and five on the left, - ⍝ integers to nine on the right, and combining with - ⍝ remainder, to get two rows of output: - N ← ⍳9 - 0=3 5 ∘.| N -0 0 1 0 0 1 0 0 1 -0 0 0 0 1 0 0 0 0 - ⍝ combine with the OR operation down the columns with ⌿ - ⍝ to get the same combinations we had earlier - ∨ ⌿ (0=3 5 ∘.| N) -0 0 1 0 1 1 0 0 1 - ⍝ replicate over N to pick out the multiples - (∨ ⌿ 0=3 5 ∘.| N) / N -3 5 6 9 - ⍝ plus over those, to sum them up - + / (∨ ⌿ 0=3 5 ∘.| N) / N -23 -``` - diff --git a/static-files/Apl385.ttf b/static-files/Apl385.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4424ab28960a0f7d63a940129cf159b4b41e21f9 GIT binary patch literal 212256 zcmeFa3wT{c)&D>Ha?al8ByA4`p+LbyDG-rMxK}A~r~w0V30M#iBtU_p1)@}l7~xPO z1gsE3(ISYU7OjX12v|WhB2*L*l&b<7ydd66RFJ44=l5A_W?xP~-}iZ+-}64d=l}e7 zo5`O0%$k|C)~xyNiSdjv8=ATa%`FEk=verZJGVaB7;nBYt7jgt;E;E`vgu!@8FOQo zFyzKzdYv)%-$E%zAKh{2F=u{o=_|πXFa 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%0AweZ)B-0?-@Mba@ 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

DdEx#ogWWUBzY|ZchMJ?>jk0GV zY(qyw!mT$~x{aC-Or+aFmrpxHgSB4;0$&ndi3-a{Aiq8sa0b9+hfSEC5>&K{Ci>|b z(kTJbDafjG3$)p$MO|5EMDx*t8uw8lLrXP1JVhZ$#(v}+f_dxmZDm!D$%Dy$SA5D@ zMREPz?2XN)?ZQ?MUjmv5;hv4H?31u6AVWdj&P{>56P-s6O5+x_X9-Zg{NgqFPSUeT za2UAXkieJV#M6^~vXO&@$>bW^$HtJ5xZ!1qj1r#sXYpjN+DvC^<@NWnFN}4Ex1VB6 zD^5}N;ltRkSBv+dN1M9%V;~imLyItDBXX%T?}vTh#n!0gfV3=oX+0A*8sU<9hF)B} zBCOZLOk@3jKbmJ8d|Lwh79##Us&fg#&k?PMhOUSlP6fVfRF|Y+g?pQDeNbhg#<@+u zhE_8D20%_JrQEFNrdyE@0p zGbOMnmGWV+5Ecf~RI-Fd38Ufaf0Zz8(?CcKLQwQk__}_&gxNtQz^LIcVqD17lPhqQ zFsv*vUBxcf!<>g|5D-rI53F;(SX6vH>(`Df40e|aG4v~1iWbw&M$HxHP=M1vH>8CY381~`?A5}*8F+w3f1Yw%Z)-dwcfHdZVc+JDO4+VZal1s8lT?^0N z_$B)%RK+@w(nHkizAPZ(^ba80;6qfa(suNRO=6~x4gz29HjlQLyUwJv(4JkSo#yKH zj2lV2Gs@{=`#CWHkwVa3M(zt|)S~UCFF})kzEF*;Oj8nwQq4>qk+eTICyAMGE5LFo z1X^qhaDu(D+SXhPg9aVV(cDBj@UrGH{1r)NI|i&VjWqg-;brXMdz#6BHiv?3ARO$a zZl~7BA{`&kdEs@jTj0SU>StC(ME7MNYp~b#fd`f753#16*A2C;vdQdRax!_VS!y62613Q z?Yf^Bz8(`Dfi)4qX82OEj5CPA;&oQ@gagrqf;z`DR3`QxC_Q9V1YkXJ-AKm&JsJc8 z3zJRzU2FN9W$b8g9p-ZIJ3*^yP|?@qavFGEcDlgC4n-XR8^+<`#NLu|5v$5dAsNfZ zGj7Zh#{d*OrjM1=%+tCv!CFmR#t(aX&5uuva8e+>J`#8@;oP-;Ld!6{O0~F-A3-jq8}ZR%1Bs9 zJm{;V2nD|ZfB^FYzdlN0a5;;L3&eIt*Pidhrf7k0mVO4vCzBp>`qhq);U%Jh+!6A@ z!0?)x6ehEo2r5NDS{=)=aXXZl>UGA(yl|%F8_1iZVuM^}3{B|amJ}dtAdPTv9bz>w zMCWxo-XTf=*3HYQ#IYn={5y_?iZ`-onwIv%8b*_4x_Pt$Tc!l|gshjd%T}}V!K~?i zu-QZ~(br_#Hmgm!P@7+>SRsnJ3I^i1J>Rah7ZYiAKQgT}MvnIOYWPP#VqX<5r&`TG z*yjtvKHSv{P#C*3>VG^FB#~vN4|or>H~8TAYJTTNkY9dp`6oV#n*c@lh+ee$Z=)hj zlv?Dw%(W-m3R;egm#b(>tVA`MAe;+o7*Q&9lK}%u2d4WP3I+!zQP>XhZYQi7`5bz( zP@O?VBxP2|;zcvj@D7zR1R0Hhj*~WJwmiwc3h1BaPTF=-0&$iOx&X5i#t`)*lMn){ zh@=W`wc>#0MoSh;NQN>cmzF^4;rSZQB1KvhflWVA=_L!9ly2%l$u2Jy)7ZaLxXnKT zduTnXcf<@|t*EFPAs77U$_%8AS7u;FB=W{Ntcq*}c4(f%Fix>BT|!N!oMX5+IV!=M z>=od_6eXlDF%NZk0dVwPwle%v4^Qpc>{+!sMk%2|++rU^#>spTkvMd~C3vPGc$Y#% z#PE7i3^rEOag_q$CHU#wu+d!sy$wD{z@th8=}tN;7+d1WcvK~c&hZhCJR3dorK181 z@Wx&&rtMifeq4?vbjjsQ@l5b~n@lPtvsAw*&|)xb*0WvlkGHpZNd-ZEl1avCS-uI} zB58o)zyI(meJDnTyc&B}S>g-Tz2+kpirs$_R{DL+6Xd*DF$@pvsv;+wr4x8~oilt@ zQTH)WT722K+q7)_;+OmpH=QdBNcD%i80y#e9dq}f7S@t=7kR5n;B75||0q#00}VrN zi+-jM63w^<9uD@A5`W&|g*6fRK=6#($$=ANwax-rb_bG$9=^QbQa zwD%{ahBBcAOxF?#RK74cudJx&7n|Q3-rqrQoe^gzmo0~MNC|b31>6B(qE>;z@ll`5 zgWn|5$q+M$4n3GAsfd{{!JS%$KsmPwP;=Q|n}%=NNDm!Q`W!q8DGH9VHhGT}43cmKoi=OHFJy}yZhiI({tJjXQ~KVT2BZ$*f-B7!^} zDNs=j)fDPRXf4>32>9l49t#j8gIqX*q0x>}4FSPjy7nQ~bqh2T9dtimEO?Ls%Hw>A zeXJUI!(&}j%e?>nUJ_+p8}1AJ!WW9YcffFV7M8)T)0{ZoHCJ>ume* zrV2=E&Jp;?z^MHtc*8zB;tfNXihR?kAM-2>VH_ff2~!bHZ7v?1n=&lK?D52XuboHJ z`|scP82&JEhnq+ihHn|Z)hv4rc8pyFIo-PP4zY+6>>{U-&Iw&l=o&>xMGl!l4+cUz zQx2pSD_#*KF+n{LB7=e}F9-4DFDC5a#z3OZ6a@de?@&4qu3!NLK^I=1D}I5I&Sz+a zWBK_aXt0-^oC9&gcinI%=N{Wgh)39WkkvenzOcpB?n&W@ ze7&#@N)crpL=+bo9!AAJ5j+jkDE7G0g=hqL!f4th_iL&5n`d|CVCABcJC!LUP>bWP zL*G*?G1h|;Y~=Bc@}J!EB`rW-jlPzgAwx+Ycm)-?<`9J7$0W&kH%BdH_*v}vi{-Sa z$5+aez8*H8u@xacE*7Cqj12WUJ8i;;1m97t03nw#*Qzd0QJ{D?vDWDdyFh z+wRD;$|lJ)jBA=t7{MCECy-EM+-(}Bp~PN868%bi^1QIdJ}^P0On3mUigp;0J*|s6 z=J5H9-HO%-fUbvk<58z;HOa;n*bIEP%_eimDtm1Y^9Qk+4nvTx zW16{#k%Y-~+;(`TNk(ssl^$Q(yT8O-pMA70>M{SdF&8ak7-Eazbf|c{e(5g(|BmU- zTa}oe&Y?PPr<}Yj&rrNM2N|hyzhytwkXD5P)gD1OTQE#@CrYqjf{*O(sD?zK0x~(6 zNKX9@l!6=8>v5qr0}HH)-^pXvs}laMYSK$4JklbI(kqx@%19pn{j4%3j_D zctACa=y|JcLAU%^?5SoT zXR;S`0$@jDGVrx5wSrn)Sjxq)i}cTl6N)anqQpA{QHNze1#)H)Y*fpu%{5{9xNu~j zaAdczJSF%A(1m0Ap1Q0aSwl)`hI8T)g8y+#u#pEB$sG{IMig8oAKiI-lvTS$GYqtYw3yLlY09WW1?+_p_U)=OX3?aPvDO-;-;dlv+D z8uOmfJLl>7IK@-NJdzuZud#Rhqa)*AzyY+p-ShAr_U91q7iQ;ORBhR(fT)2(nI67> zd#%Jd)A`VNQ=()^GdB!a*lv&Q~6a{Eh|9a1!)WQBQ{VI!r^s}&gG z1XBAn3~Gw|t&!)yS+0!oi3Cc3XrS8}g-Sy5M=A??0x=F5IXGM?Yz9mnl{ZGVj6JQA zoeFfZT3cFaH^qAWjoW)3s2nj3W+!+C>*v*HS6dgP6f}A`xvjTMcMn&6c8`v6T$FmphQJCaW8-i@k2$6xwXp^gVJJmva;W=9P5yNc+$qdvG1e) zVxhmgwHhkIEUdTFGPW9y3ImMs*C{{~HsME)E==N?@%V&_p$}RQK1lR8zYyhTqR?$H zpN3&3ZTvfgM=gxKqqX1<3RY^|a2ThEw0{xaR;itmcsjwlj*IdmH4Zu=yzG z8Ob#So(`Tqi=H0$K-4ipw>kPB_$f{IbT@<1l#1?mi@EG{2+RMyA_qd2!Fv)XAmqgt zA-kcgV%kN2tENTBHvm(HcUL9=GjuSRRKj99rdBSTH<`s);6prM-+j=uiZY8`Eh{&n zUjT&fH1lOQY~D9fotP!=ld%!^Nfh;^<8*L1#rUQgqs8)*q-**pOedY}C-w0FP_fq^ zQmsVYmA@mS%^0~dE6}g~3aw%H+%zyx8ql13j;|e8khqpq_OTGmm$Ey&?Zd8B1e>dP z6_T)ouMLI|vh~$YR}?#qoq!!l1*D3uRw&ni**Gyeo$EKg!M-ac(M#0C1U4gss!HfM zfD2GxHwB8=<}?kLrbh)+KbJ6w7jN#_R6X-^U%{=eTj}RwdZ_(|hYF4(`hN1ELQs*V zJaA5?c$bsxu;jCSr;5((UvIEKw>&p#!TW7sg4zKmPKg70p5NX068oI^D@1X1il&(m zQ{mrGw;=VIQ+k+FZ1Hgh{9SAerT&l+%;CJhXfLTLL7KK za6)#C<@m{rqbIZB@C_LcNdfUCUL4POM?gFVE~qWekv1KS;`ruos|Xu=-dQW6Bn0ehQQa=VRZPJ<*#jCY?EW+!%>r%T=X zpnYj8$$p$cse`5chcqOoT8(`v;2?8J@#UBR(!RU8>;GZzJ>cZJigfXN?(H0I_r0BS z4%6K;(=$CiIrL~W8rhO8S(Y@CZ7fT+48{@LfCQsI8ReEK|+jB;5 zWSDq+B*R(Nd52R`Bl&?+)$RydEoun$B}o5r{Pb_ggqKMA0H0Ee=~bwh<#_KUm!78Z zw&Eqc6cLNSyJG(~reBcMnv&ju>>!H;GWM6c?n!3v^<;Jr1d#2u`HziEE!u5?;j0(e z_ks3C>IWe5J%&noHiR*M0Nltfr_JeF94f3d2KI%yY{I(2XSPbH0oWv2kVUYYA((FU zErC~yf5IPLVYr6YBCt#K&v!Ho2+R0qR!3T&w)P)ll0IwQkNKy2@OpALO!W1P2DC!q zYwDkgzgznp=4a4n2G{_f#OZ371We)-@RPE0f53^+=;rc3%o$0mBb`~1w0SpJQ(Nkg1LZC`L0v_<~LROJD0uq z6|Z0o*V^w@&u@O`zU7wN;3Wi1kQ$Vhum+S=@pXvBKZ5uw1N(`fNqB$b(qZ63%b2uU z;EZ%>LsWVjG-%%oYMPaKMls$`1PD-k2J8 zhvXs0;1FiE+R_$un5PV;I9{%pogs#WP?)+EbixtNI->tXA8P&J@i|yX@Oe~$*MCR2 zBK!#kMDf+?6Zo%y{{r|gr~jGhzqUS3f2O}b{rCGGI{lmb*1mz?G>_c(!AIqd*R zVkWUch1Mz1J`dsyipyN)po26uY-6YV#{t(tGr!(XUt@{rTgoP3=-*Iee9mV}*BNr8nSLEN|^1{Q7Pz zczt8R0Bd5B?VWtKE}a8vq88{OE}+4Nf~)L6y&8CS8|vS{j2UQRbW46+cOX|GhBR(Q zp;f%?z$1^WzV84A95)ZK=KFRy#AI`VeUZK&e8=1Hz22^$I`xU5uE`vD1L^yuZw!1I zz7qX-+v))fj;4RizW}}hmzI4Nb2RwWWV$mXs}*wE5Pr91q(`Zy-1s^LU&_N}!zAYo z*;d!y3+M`cP2oN+l^H%3QvfVr>VreWWNW)@=dWClvJ+tfzew~oVon1 ztH|zHWuH~2X|a=ke?a`|+70w|-zMCr&&t*(JY!TOuDV4=B?q$7>)C|K&>LSD_NtCu zq_3J{+nM{`dz-hdvQJ=;_J6FhFRtBy(Z)ay@?C@#-Pi-Fpc-IFMTgme3^vy|qpj=f zVlV4BBFx8T+gI;xF0G<-dWjFoe)lR3tzN}F#4f;szn<@`3pl-~jC)A?OH;lD8Lag1 zsU)*YazG0th&7+STcpH7iwePR8`ruy^Q%I4yH-!(d+}qPVA~JeyY?Qa9Ud#p-;@~io2#Do zouF|WXW-Jb8(M;$oyJn?TX}6PQeZAeDfa0!8HH4s_!0+ zo5tbj`px$cCxhuH==gP*!7zvoGa!8i{ef5F8c9})uC{h(*=KPl-v?o#bC6Y=lkS99 zL2ay2Aq(RMddJGYl3?)2CK)9LhaY)m5ALM{_Y&ZLLrB4VI({Y_;%ncFG!zHsia&3{Az=q+# zUTs@JC7D?ikm^$TVgwg?V*`0MpPu~)04YyEseJr`=#Nq-h`^A2ql~-WJV(!kGF7wj zr1Eg&E|D}*?geoh{X@JFwNMTv$$TA=8zm14^s1yrAI|=uy(tkOq1HrSkN;bGWg_Nl zJ-PX-JFh=KdF(_VVcCBMZ}lJ|A@;*9yB*HKQFqkkGkb!sGFy>Wu~<=1b1o~xZj;Yf z_!oqtl48!XoE2G9Fr8&R%6Ks4MJ>h%;t7+@5sXIJDsUTTvH&U*VI_zNA7p!I*h`wl zki+e>rZx5no8J#MHEP%}IMSe!vZz+@$JEhk=RvEuh|X?vOuSPD@#cpI(XrrX)>Fr4 zo|6IHJ}4x`1N_Zy_0Nt3T#nnBNwJ!npQ(dM3Z=@!CBGu#%9=6zzyy98N%BPxtG>F^ zeAq%vuxQ-?Uy=vWHyQyXU?IR$k3u~DiNm879Eh3LEN6h&jlEW_r}?z|??~Gf5x#=guW zj{kn<5hhF`YnMPDt`D8|vIo;(92P5zIs#Qcxnslo92C=x@bREup^O2+Wk$!}al=iv zf=6*!t)Fs6WA0Cai#z1W4ziCoSCUcYbVbEoU`!iX`)I(e1hJ`@k@~opMaNcLIJJ?x z*2H!P*bZ#2kzH#BDm;dyligxU0{n^bRT4<41h=-wq2VC@Pqz-6jXkF(2hB7H`UpJa zUm#e^b3nb&tEX@&#cVv|dG}pN=_-(Pz#V(nyP0fr52)f5nL_g;Y&jyjJW6KmAM-Jp z-P8OUt2VbNR^k&p6Z|M^kTxPf>#hp05DH4vu<7GeFdKz;5~MYTk0#L3JDXF%)D=F0 zj;$5d*gX}0L3Lu@MtLpe59Y-EgAuiP4!dF%l@Vp_!x)h(N=;>cf_CZuCf=TIUYdL( zaFvx!IGA5RHN*iFo)@r3(4T0E(z*mxx8X+tH(X0z>Yb$|Qv z$Zuwj??V@ld(vjgsWp;Ucvy=pCmcegYezoJfEN>neM3Pb6k@`dL57y?`0ruSp~=;P zj-)R&fbM`DI%{F zLhiwe7lD@CoS^WUOk)pUIsY?a?F^w|L4}&5vcp*B5X~^O0y1^C2jqjOnKjQ=(e9RE zcdIm2*6V4W=>cEc0J}@Im{SK(=LU@j+WJxJ7MER4H%*y!#hO2Lxm;yDp4`Ngr|nS( z{^frh_Foca*MA{K!8S`d?NMX~F_#u*5YB+WBrRs9fXBz1yXTlhyH56yLZ5t&a)fPqM z{xgT*$*g`)EPB)k$dNMmB(WF@`ISs8s(_$`2~+EjVOr%!fxyc(f)X(HQA@#+!_zA) zCGaXou&veOHHCyCl2|CU`KeP7MJF=^D17TJTiTh-buvI1{x{l{3KIGHNdSv18|x%ne7L9>r%%~qeMxlJ4$ zT4d1-$^~}(O}2bwC=4z6pUg}E2%&fiVu$Uh4+d(23$tWllry$Pj1kTv0V_%kJ-E`0 z0Cqm3LvE0r*Zrq2pxI?D&wBD+Ptm(GrFil?Qv;>MYz0HxKET3m z72rw2Vy$C(^Bu53o`y9nBr$r_mc)Ei4SB`u6aECcGI-TfvqNw?o&w$l6L3F={TOE; zCGWY%Y?Z8%DaYOb7(U89%^%0ZmuzA&$io(BSOBR1YB! z-03JH_#hZ9<_N(t0s_vQAcs(;1!s>3x?gG0n9%;ywdKOlPqe4{2J^BL{)itOYn8$F zBB6l9z&yjvzy+q57#x$VvV2}5E)xzL0|S>{yXSCX3_z&JnKO%}WLhnVR^L)`XezM< zPY1^A&ixpO!VJNGr~Vh?pm-;n9vqxb&V=W;EskEw5NV(B=B4Qu%;ffqUVm!KW%K2u z1yxjw$0B3l!P@fa{|3%D7!79y@9I;)DdJ)eqCaH@o;N%t*sDS$OTGqZ)dcDSb$CJn zH=g`o%j;mhyjhIUHF%ccI>%7IL@I=`Aw2Uzc0lWNmpBx+Oz|~=T+kT}MtcQ?WB2I| z$Mv-UG5}5|`gF>piP*pdjK9ID+E>GVuu|WM-iquI+c^82s={;l%GPU9)( z2F%u6#%Z;n-pN+p5X-w_hHH(sWM)6Iv!Zb2`U}{P#Z!<)--e!#@UkEVg`#LHqT?op zT5}XVR>R0+EppF}h0!_Uq2jLri;jd5zbW$^l&cr-Hy!gE0U=Xqg|%$W8Ai{{6y z{ptQKwVj915`$je%v2DhN@6N=N-Dpn=*Pax{z0f*)(fiS61sN{IC8KE6;rcrpc`dZ zY{na6OLZkCyJPaK)fmbR28Rnp8Nm0sWOnUww>OI?MoLNYG>q!aWPO+gW3}7S24zx` zHLssoML4_3EUHEkAb-&W+WsqAao@kaQ&xi31hi?P$kdUBsWiV6#Xv5Y!fEvcQhC#2;G=_^N z2#9AGHHc6t@_JJmHm}uW< z6RBp6pBDHiI9S{kcRakxfoctFX91XDV&98BTS;C&@`rp_F2SF3^6|s_9e;l+97g8Q4o~oek~N zIfn`D#gchcfm>qW&>c<#t(B1(T2a|{YP%(8ob9BBO zHP3Qh-#E_Ln8H9CC%Oh4tUR+AC?iKLGluWX7c>E`Kh1y&nwnuIsw6L>S;g|6cw7;jKVM1deH2r*#*FI2$-fDxkV z0U!)*=%(ceLvmrQ^ec~gS{}Pb5i51GVqb_=wABpTS&Fz?DUl z2Y1ch?gv5yLnK!Cs#G}9+JSiWg3tZbHiKUw+$!A&k@Eag#qDra%3Jp=`7&8N)P~Q2 zCIJ43^F%9<$7qQufp9eKMwhxhs-RQEYIQgFCRyTdW|wapa@bOZ?D>bG?KTIHs5DYt zc2E-EG>NCWg|E#MAKjZs*lY{ z@KCKckB4Gy(xrTzK8l7`+Hx~BmZ8D)qcvZs;vEj7+6I6!BYrOMG0LeSSE%AC;Lp@B z0F0JW@PcYt5AEPixylZS*T4)*{}4{!yh20{_B3=}`&t&7%=v0tKBC5e7!yiQ7jFC~C{S3t8$ z&Olv$VjvuY3VnJsyRq)|K1@ElJ*?)SK%<53{g_ycozK)nY5z(r}!?}q% z#vtrET&qmal!AEZXCwZUJsJrnN3oXwe|d~4T6-&^weJZBDWcdV7^a0FSd2+0x3vlw zT3#BuqX%GoFZo^IELJEB17+LlKcH&ODB9<+xqNOi^(JJ}TByojKy-Pump89akFnpl zQuP&|Z@5^Bgv_E?@`lShEHR%SO={2qlw1kalky}mJOPmo3;GKK9t-S9Eg5urFzVY} zj%TAzM;atuVYiW8lL_X5XblVx4a;HY8QU^S6qQ~*FO7+Penpj3M<@!;TQtZr zjF*p>JRYAbH4ESk!YRpP1_A?TlLkLUoqY?IcMy8!%M0LLwE}$!)*e#`4fBBWYB3jS z882xfFn|+9*p48cOdUtK&124Rf#(|du*ovx>NUX8WMF;&wQzMs?_AWH4RoIxz z)*oX(L(fHsI{gqG;0c5nz@)&YwM+^;ClC8@bb4|c)S~1<;q=i+{3RFIUd_s7VYPCp zm!6gEo8W?VsE+3C;FxFUJE#GaBNdN;|Lh6=W(J}ti{ymC6fp&Wk417^+Yl;P5)xm3 z8|#LXjM3Z%-ySx@Wahr$9?*$M_}Y%}j@0z@N;vF8v#Er^U{kY($w-WSD2RqJ4A=bf z;Nan$JC)9yQTuYpiB9^+_s4gzOl}EhHM)MYm;-}?10cwUO)UMQ!&Q~a}V=2}VzU!MQ227*}p6B=ctVCt_L zabZ}k!x*x0mi-=ey6-#{qp3nBG&6sZpI z9pY7KY5t{wx#WN=ix<{?qREJ8(qIIMgylXA7X&l#V73r411JN##)K^F+8FvM&!mjk z>4I-wNcwC^3@R8gZIyNb$vuN$giIUXW<53J;rpn&0KReBWk8UD?T06z_(Rt;Y^C;z zxG>l_FYXBTdx-g{tWU`@90Pubj|`)K^j?!_#ms16{1vx~zfCoao@@$Jqdfkid1|0Q zlVxmmt7=4`Vgrs3wvi=r5hv_A%SxEL;}2!UFhQ|#ULUd{p1oqMHm~MR&0rFu-L5zZh$gD>El95*rjN#Rhp(tgPFanZ zO%o?z8cVz^kjakRoTZ}1{Xw6S2(CPl4k^F5V5Cv<$g<5WUfyPx+Qft>VIoXZ#P`7q z60M&?wGpF|JH}G@0ow#VEAF>b^&Koda9dP?r)CPo{NF9Rzsr5OUPU0AzfpxBqsWE9 zK_JP5coBM?7psd~ufF<}9rH^sW9HR-<g(_lvu$_H29&7GMizcfgzQpY@IvqCA_fjylX6?9Vr>uWll*Qj+ z^$Wso%HYiLJUo){1%wroDESJ=;%Ej*i?kpKY;+8Pd!`+4`h;F`LWkXGAcKm9cut?Q@BW1Cz<^ zk0A(q( zFwmE7)ezy|@S^lnI*i6Ho!iO2B(~f(@c-%H?f;;^pUB?6gHjZFE6F=Vz<-8Y$W1T zh455JF$bI$XY*ts`gW z@ZyTOBC$E~3ba<>%6MO@Iy2y3Dukn|nvF(OuT%twu9}HO^3881Bcf9YeDTsPXi#1* z=BB^mbE~o({g1g+hW!Q3KZDHa7;f1?;n`XY6kZf^VX%mqO`}K}?=lQX3x+e=*|p6v zkZh!zMmC2+&yFCdGX$c0$ir*A9Jtk{sv-Xn?q8l_AKWs2Rr&71h+=!q_n4S1VljB^ zCYKAbq5%X*W;ruYK~c=1guvfCRa^%5R1G6G5#?b*6C&?JsB6TMExme5kUiSDfxUR=W+O_SY{fn|Z^B7gg9u_`_UeM$l^fxbyN z5RhWS&Qs}{gOU02vc z)8>$DK^E62{nyf~?stnGmwqwa4)MAY8(RBojI+VCIhOmozsKZP$%bBYEBnUx*fw;v zDt_L{$mJE$%_3l;-a|qKHE!4dKyT9^0uBi-q|QT>E{D{5kqVN~so_%7c~cj?uG9pS zo#Q?Tzr%G$%z$~y?Hf;P5akEs9@R|51Xl0F&qHB{GyLH%Qb=gLnz$S13!o5#{w|a2T?RW1d3LahU`&Q=zYE0~%pGzN z*~L4W|EpX4>qeZ8;M%)`Zq+F#e*O>=h0N+qiU)@rz#u&Mc(3dZpdIKONNbS0unP*f zuN1U6gf{0c;N>+o1B9ReKG1%1VpBSU%^P27en!R{JN?Xy+@2_#NMj`TNezglKJ6+!4;eA78F*)wEj!+bV!PMq!b%rv>UKM;7-$GBfWY;&uodD zC2b_X{T?4z8r*dZxa{3laTh!ms%e(A`<1I!#fia9nAps26df|kv$DN;O}DHsr)-!B z%9Lt8{zWf3@-cVEVi22O_$>&zn9bsSoSoe*xQMPvfy=#JI7E4@5y2G_(o9&iq5WY1 zVWtI%e0V$rzX&YI=>bebmZ|le(^f)JKVfNT1;El^g;a(m3*SoUX($i!ls?MsO#lnG zX}P({kfZ2EvxJ;jxwcU|Cn{gqaAD$6^36`4SEhduY9#ZM0|htSwkf2zFl*`cUW_4< za%+!tZNhGIw&E8+ufXST1y#|^g~+ppqcqPbJ?NJ+A| zPWbR0(8q`{iL4j68q0zMqk2GoW61!UHrk2N!L{ea?X&_8Ord~cm44#(iYrFT`iPsGJ?OkXAk>Hu!@J2f5owxk)hc*RMYdR1sr63+m-#Uv1BBYN_O-+42aZGM$ANCD zkU49AZ63Q*{6*GFzrys8r|*aFNHi%tDTNOx^arwZ<06I)!GqalW4N5(vY5~22aupL z6@9rK+lw=?Ou+Jyk_=u9wV1CC46;j6;!>T80Z7wu1ap==#c;^2j{2VWSyX)Fe^$NC z(!V4!_lE!&h5Y{Y&xl*Z`{45iQNzNEUxMtzfN`WyuP52LmrlWi7T`m;{E(a8Vk9-$ zpOpW2a&O5tzd59uY{8-NpaPQPI(qVLbCY;rEV5kTXs6JNgUQK|$y6T2>&pm|FhF=r z#u3aDO4X!)_%;dt?+|?9UkaJ8li(!xeUSU(kh=mOs5WfFbtzMlRPZWl=xBx)BriXj z%>Dq1ATW_B`blTYo)|}3Ny{L0Z}yh@c4sj>>~|PEmFBlx-YhFNl9tH?QU__J-h6RM zj<-X9z)(Yemkagi_GWZG%*Y0^}5X1>rr63i$V$m zusQKO-)r4rQ(lv+$T$XCpxx17KL_A)NwwRg~<<$nA@_8U}qi^%i_;~O4&~6!x5nb5WNj3(h~B_qex?HMSfYt zAd-zb41a5rV%LTwEJ{Y=hPx$19F%W_&w_z~BZF2TzojCX0x-kfqw#2%kob)OT_aD`rRiEUTw`RjU^^0_ntmE6%L=x26kSw zJf9fNs9AM%b}7BQWg!(cyaj0li~U}U-E%Mh-CJzzGs*h4ym|lB%*^z@+Gw?gz-s-M z>(_}F0m)t!wvr{929Ld47%?PaiRKYpwJZ@CAES)l#Xk#KOosED-?Z%7ahYZ0?Cs_9%Go2< zeQ4$)$KEcuutLRQd zdp@8BbQIa zX>9LoCO3b^aIjVkF+7n&T17IxL{d|vbjCK;j=R|UlV$e(6i9{JAq< z{IZuaYa-A*I5EuLKfc<$l|6HVzJ`L8wLgkK3`8f_(i5wg3J4aS^}iMi;;*s$X}lu~ z4WBGzf$X$p5we4NT##~-H3U)w_aE^Rqj^;PK~_tJn33vbr~yEAQh>PXrd~l29ZDrL zDW&`qMv*^n0KhPtBgt+=7lLBNtO$Z40_|!E9&Ms6cg-sL?3sZ0_GtoF0pX=s0?OJE zSJ3JPkXjU^)PGOFlehNIJ$M~w&lY|wk?6R%G zyLaN?_USrr9vaf!)T1mOV-54iEzO1Ll9+wTCVQ+e8Q2o3UehB>`2>oXEYXNx-)4q@X`2==SK{m;5huOx&dIfV* zFj9twTY!*>r#VnWB3ZDP;40Rn4Rji1WB&ReI1q1e`E%@<`Ng&!%8!6^HyZOa??y|* zo7xt28I^Sp@YyQ9J0^L!1<@*qCYSzwwfmv%1Y#MQwZsuPnu6gV(ZGX|(al>G^se1d zE?-}CqG)#eaM;Z*Oo!OtR>G<~(!6^F-~3@OvIi0H#kRF4fb3t9v3~V3YG$j zMj>7}gCWsVJ4ETh)t&ON&>aGOK;1VV%1>APWq;Tc2*1S?RJ`sNU+s!2(MGoteZzZA zen)<|(tN`1MB@J2--`u)(0L%FLwAWKu0w7i2K@$J57b@2UAn;tlK|Q(31_Nu6lvR| z@(ySkkE901C#ZpPlLZ!uj=uT)%1;#EMVDOkiZ`%3AlMmDlz)Jtyop^b&I0M14mH!k z-2KcFY<`k0u6;%P38{Ai>V21PBk0!oV2SgzZ%H8=5pr3~@67=@9ROUY>()U}w7x{_ zTYy^A!C$!f+WjC5VB^&~9tWiMk}*h(lUOi+TXRdgFzZXYpF!yo}*p+MN3A_JCvcL3eUof3AILgNEjUuY5_5c%B#~bYO7glh#+%7nW)AHD4_UI zIvzQ1L<_CSbdY>rq|rj!=F(FEjb@uX#g$HfOi^Nf=WyB`_dDrN@laSsXBmFE2P(W5 zHsB+$0dHiNu={}-ak+v?cXmV$#@7XRA}B|rF;^_$423`5tgQ|4h;x+^FS%%**P{|7>7o3`~k_#R$0h3R2=?mmLCDOBysL# z0h1(^)o`HN*tvUb>@*21M}{LazZP<8p= z@~2hiJ@b*|wf4+2<~O7g7Y0YFJ9dpth=nS(+K8UO_)$iFW}ompyg(VElnmbWjs}Q} zKw+$p(JS-`NxCmeZsTnEQL|t4#wWpQBoqt=g5g*o(EO3p7nVbzU^VOtW8~JRScSbh zQVoTJ;ZQJuUh9u_xN+GDesVdr`;~E#FJjjKX=@mS1QS%D;mY%(*R}- z#hc&AM-$UIze8SN=;^ltF|eHcT8%uBEeMNK!crJkp6t(}ZOO6(G~SrB z*c)ZzsZBN(t;yUP&M>ofabR$3S|CfVT~Aw0jAG9>`6|&mo}MV@Tw5Qac;lb9zYueS z>z0%mlg~VrxMThYxrpbst>%(*N4(oNuy+r#UFNX&%&4M-u0jd0BHF#Sm>lt(omY}q zNzG?=-Yv~ikT;_)rA2gTVVwU|pr>f2k4kuv0*yi8Odp%^QL|bpZqE%=^M-&Y6v`CQ;$mKjC_$ge_T&#B>46I;udUgO)BotgV-%c#J52rM8TVwb=#1KrWE zD15LfVhZlO`lkbLeHYL8{UtJf@4cNees7_SU!Xgu_oDT?flRs>{&+};HWYoftO&UT{i+&}E|a@mdnHkjU)mC?w4+v`3k+@5Wwv@L4++-#R2N97T@$W2N+` zy{Bc)Pewwnpv(LGx0U?1;O)<6pDolEU-YJl;d~zC#i7HcylGnq&2#VJ!%QCC7-oWE zC)Ec&h5Eq%f;ZnGoK0D|y3jC;2;0B`OLc+-&sO6sh&Tko(uLVvA3)lM4En@4AC&Z@ zpGCd9Sa*A2C#WDGW9j$32c_>3Iig*&uexZ~%W%M1WfQ=x&0$Nj5+-!$)~6=A&x zu^XaF0nAl##5^I80fwq|-RX(6E5ggZxdd(uQbD-H$L`)#^2j!r|kSloZ{uB{@w{`Ff>-oQ)(d${=A z!HhUKzH=<$@wn~9srG`{ADs5x$;7d=9>Ue(lXIxmr8=cG%+r zNtF-{g>6B^m69jCy7q4hD6Yjf+{lW+#H@X{ zcX#eWoOdpH=!3#J2Fz+57M!$CP7aDH7{*&jBJQ9e8cJfMX*`A^@(9>Vt@6aXzqE)H zxelPE>GLSfPr6E_8We9@NlfBifP>(LLyV5^+}nI@H6BydU?8*evT)HI3xZ!AVKsUM zO`cm_27|$K9_E&XqNrR}hsIK#aeFeG^*BA~g#hNtB)ig>lIyW#8{P`Dc5KF7b0b4r zx6Ey6ER>(YBncrwCSr;BD`Bq^cUk-;H0;(f(+{0Bsk3UMm!0kg->X@2fD-^;)IeZi z%;-zuiTKAa_T1RJz|U6_h8xK=#*|oyuNu^RG|@AFnwO2gDdGZ(q#(hcoKBC7Qp ze$pJAg(L3@Ngs*0e8KO=++Kgs>+^rt?=Kx_udFQY^aVZP=C7GO?D2%x-scVbLJvO} zjNa5ECrzs^67ns9w}r;B1%fRjfgYiFEo-U+tYA?nA46Fy&AC$^uk)OK0#EiFZB(>h z0pQAJrCHJEw&mJ1#kzG3TKAIXK#!pNCsGuuh76wELKswQVXzt+K(*$_@JxC>l4BxM zuSXhsUhzb8p}UO8iDyKQx5a&uanWmqp51&8mmVxpBz@L~GLglE+CmW6y8tSkDLt;` zI7p2pxdK12or{d6lPQP|;uP8n6p=8cCG$cmnVn&NoRl>4eRU*rGXR_I) zw$%PG3XFzYG=KVDap=@ITeP6L900>xTz33&&-8x{w~{QaUB3$~KUwns5mc6u$bo^@ zgE{0$sfmv$tVl2ti35jlQBi#DG=QJRAVkTK0uO)(s)_ME(MQ-T+CqshEHR{aeh~BL zBn*&op%Z|V^F$&YsCzreMaFQ0tFmjy zj>B7-Zp-x~6qc<7QER7&$+AE)#xY|6)8EY-v)nfB5X34HgQk~rTvX`B@Sl@CJ zI$BcY!yozBY9(_?TR67+hI1}EcIee_KKnUr|3!_1e_-ZA+t&V37px^0`PmXsA_I-c zASV3iG>-DUoC&2Xdkzd2UfEu|M-Inh6^m^3UisSVSI@iV z=uKzuITmu7($VA=_VT~lWe><13pxtHM<*R!IdInUp_TcyzwX_OJ9tmo3hZ=j9`C6! z!6+jz4TGi_W(n;|V>~%oYMHy%ix9qDvv715bSf2XFA&C1L_p3TJH^X|C26ESj$4CW z>f8nP*=>OXD^v58@;1p~Ob6nQ#3EXZ!oh67<5q0G(P;RL^gt=-P@@amnCi7D|Jq(X z`{6Y?ha=`)`%pH^s5>$>e}-oQ10~!+HJV7(W6`)gH8wdBcYj7iaUr^PxV7@u{eKsD z3g@YQQ5WXGhBj;y{KGasdN~oVwdxlej}RWqaBcP1s@)nuXaK!;tVX#TGORs0r^k0@ zRx&%`7WRM*MwuU;I;A?eE4w|jE1#~7o-e79JzK^PO-$`=FYlx0S6y*;Zbzd?I+e}t<-Op5qfGqIiSh?Tw>_qzOxi!+M_yXr7wTttT~ zA7h{L1QV|2IeW(%+t}R$qDl2MXBS@lhTikO8#tFVa>2F`UN3I=MGRx2S22g?ZBT-E z_*JHuSMA!4aJm?J?M;C~_P{9_cO>ez*UN`09b#OcJgqs;KD#{?YyR$mBZKAWUtY%o ze{6v>TIZwf3})(*&+*!VkV58Cw8St0YmN{CkRjR^UX_A6dAenph{;K5|4|IA+$Evm zAn+{AI=uP{fCA@Tof5^PuI8@y?LQ!~zw;!$uC<%vzkY&MS#8bRb6)S|-WpPow+`^= zmOoZHf*TxDi^S9C^}xJA$H7n26V+JXe^*E@xGuZYmXKA?9UmF?%75`Hd#X6s7E29+ zb||7c-SO}K&<}2Yd-F%l`;@R1P=`NyU)OtP#Gjj_XomDz!+G@9||1B`v9tA!bC;c}E1vZ8lXe4gNYuS!|!tX-UeG-Qo^9 zEUJGANGVLR6V4C=s8rbzgCNgl#RL=Xmae4LXlwShl&3=opXFsc-$`;uqPQq_-p9u{9)2%|*vTE2h!y z=s0_m`R0%-WPh!Skugs=%(sMHPWvtBvDN-f85cVM60XL9xI>Z3nYGRZ9R$4`+5C78L^)Kn= z52^4lsExDV29@TAfZ!N0C(LKPwpf(PN(69?iim^;6Rs0~!+t2;hS>&~cTFi*cznOf zOdVk3?1z=m(EMmMZZ6vGXRa(=BwbmMj0;9-%qN+$wXG9~cKHMhNI@CP3f*xOMnR(< zLXVkCOO`xY#?pgR)?q2S$j6<3@x`8{^v_+g@r?ya;2QglXcXVe`HZ)s=RUP0j2DE| zFeFsaf@4boQa5fX16m;AHH&_hR*VE6%i~7w;k1&Jwyg*q;a#Z5c|#Gv0^X5>s8qXs z0-UA6WH${&(<(LA)07XN$oBRY?0NF#;%+NWzL3&|} zVjOH~*9GZiUyAS*yHDr%ii?7gkmnK;yQScD&8i`DXuf$t0{{9@$iQ9;kj3Q}hr)5& zZ3C4%9aO(u|Gg+l@8a?69-L2Fk6jn!Wm$_~cT(3(PY}!7qR8#*;I=kG#tlk|7MX>s(7}&Cl-DcSs*}0we=6Q+q3mrJa!|T6ekKzmm5a9wfvO6PTTM~fQ(PGbS7vE0 zdeDY}@LOl97tPPiE<871NZ@&v-h9ZXyIgk38E{)h26xO6wZ2MRZPNNPhwJQV=y8KABYR%-5VCT?3jQaPndJHzzRcldxH7S}bxL zO!NY{(G#vdIUDxL=BMqBfDydYvkt4@#30YLxcm2u??lAS=8CdszJ6+)FG8^+tM8n8eh|ZZ}b%AvZA!T38W8Y?LO}O{n&q#zW|- zyNRBqJq0hZ)U()=^%CFNy!s`~1-@8(573!$U;&}Q#7N_@QBp{MTc!G(PA$Wg7n+i% znN{Uy_spzXUTDNUiDLsH|BUxVuUceN*S|A1FnII_&EE%7nY%u9EIFP@4B=7C4nDw7 zUS2UHT!+i z)k1XLbi~FdXXcuJ-wvTqTrgy_?Et&wfy8xqpb5lwPTd1VOq%z3%C4tdc6Jgzr}^c! z>5yV-0swFa^ogkfVv}g<2hbyJ_zys8S1GN{K%n(P>FB z^bf-yX%D82hlQ9hgwYvs@vaq--Sqk`6BC|_BN8sPDz@{yVq0x&dVO@BLveU-IXRzb z*KOHk&(oxJ7HB}DXy9o$i@u9FnInm9TFR3j463+YFRj+SxDfYZl2+5NhOR}XTKw{) zApk+hw3C@frtoBZ|MNJQZA8bio!IN2M_{&E3(KZQW+Kfen0k87qEq~nIfTQV!aw=` zAL^1{61IZf!6UtcV*x5cuHn~k04X^l6Bxh?zTFKlKntVJjtd9q7k>4_1-Sb}TmA6? z>>V9pmKF}fM~r|U<{)|osPCaJW&e&-4xhhuWq>$mGagJP7#LxO!SeR0;i1I)bR0F|p9I?VP6P%~ zn_%ZX0;sf~3IfB-pUk|OcU<}BJ-Ow^&B zohI))B@80|p{><6HN&Sg5M8_GeKl0i$#1PDa7R{R?S%XL0saJ5S}BW@*ykozqvbS2 z;V9y9%8W$t_C@_Ii7YJ;B_=@bo-(3DYmDm3r)G%(ce7c{a8Jb8N6g;*PD|DcA#0gX32ixhkU1v? z=6E>FxMiO=LvudRY0mn{g)Ql_zgMm=iGyf|iokz7iBwd{>OVSjhLy#Q5SD!^(*qY; zHycM|t;kOr*aR4Ahk31CdI#jGk~MAbQch0vJIxdC7PTF3deCm(G}gzS_Sw7VZ!)El zup3zyLHr`J;!)s6v4ew%_#=Xd>GOD^!37XWt*&+e{vZk4s)*&axCkAW=zXSc+1}(G zd*bWo&Q8~+o^$m~%Ilw89C!uB=`J67L|o2Ydv4D~VYcsVT|D}{r5%;Th!nQHY=2=J zv$wNYEjb_MazaGnQb~7+nYM62xukj<*NH^!eQcdT($jkGN#-+62LN$BjnHnf||qQHKPJO$x8AYF`TwZecy1u$`0KXIrg zyyM0(YoJ9s{lJKaAGyT;8g6qUV`AIExZXZxe)7WyZ{dgiR_*O)vxOT`R?rT3T08Fr z6F4unt^G`U0R{t$7r;C6y~7+w(#erOaqpmxeQwSPws5geNYY0scWt^uqA-W|MHugk zeZqzCGF}aphgYlN5Z)Mqg=6x_S@J*xXa4j<^0bj^J?|0rG-C5!u_@FSpEiWvo}MQG zG+<)AC|ba`YC}zb1yM+77#K&3;4=sbn-Bf{DWrjs#OB~5ibHfX94DGUL(OP{5jidb zy}(AW$IJMbZ-J*A(xWCM?$NMN@BjAsV6{?z?zN}RVVHPvNL<`?WM@Unj8xH66Ok@1KSM1odFJBl-$KP`6=#8_}Gc)DEp_Q%2w$vul>5&~HHBf~oGFeR6 zVK*ETH?6v*N4G(bj!`slo^WOd!t)vOYPU9N>O?i7{|1&(q zFxMpUVXjF_q)C*|>(VCDB0C=wsVfpCA^#Lj>fN%F*P>+4j-0FxeXw`EEgiZLI&?l^ zVPK1@f|G2Kh7d0HAcX&$w5RJ4`!uS~T&JIV`t;^S-QH2tnV)l=*+M!4G*P$pY3t0N zX??mj>f{yXb)EZgvf6S(=PDVzRuWV3?h>Afijuk{oK+VP*yjv_?JQvCj&e+f?yyoQ z0z>*sT#cWMg7PPI<>2b5ii6@#Ofrop^HA2Bx2};i(E-SLO+I*JWF3 z7{f%~szYD?Jca2@Oq{&B{JoZ>I9WwWZe%J%)I*+Nk07>*V@B6tBOVm2RJF0uAm0-p z=5;VI*BB+UfeNF1N((XH-}7#U&Q~{i*yAGT#Xt5&5+dg3{013-TT%a-6fzBe5{aRr zjQI_qbBO^3BlD?~EucS#jF8Y~4mcqo8;M+3NY&8=sQxu}6}a^A(S5v@=YF6RnPh=2yR4X1DpHjvzaW`WenTi@F)k0_jEb z+*U^ed+wn_NN|9a4rd_Vhwf6`56)nO=5xSQ@}R&SL^&seam`+gE87^BMkzab8v)1O z5|JQb)ZNhcKr{t26WcHQQ9Sl29YO>Msbu#_@B?}@9TLy*h7z>ftH$ z=uP}j)Eh996GVWjtj7^FKEIKr+9YFVj*8Exmo9{Cl^)q5f1+$XnTr1VcyVXYvPnRx zH?t?LKP>JAS5Fie#^pw7Mo3nKdR|CDUEP91Z-}ZxU?3u)vJT5MES`y=4LmcA_clEX z+dnXY5l=$>TB40XvnN{m1^75_Z79IedX-QO0Br=`i3oJy07gx5mKl8lO;n>}@%YEW zekC_RJyidYW@q`;PrJj({Wc}z!8lL+oB6qe`49%x#`4=YEwig{iJ2;Urnl}jO7oTH zvCGlxz%33u?)Sjk;zs0-p2G@o5;matQTP^gsH~oHZxLSVOhv%Sp4hHD+naxp+mkt` zQhM%*Y>9)t)8mi&bIqGW0r9>4(TcDmkn*?U7a(Ptq)dSk;UuNplqPJ;_4*#;&?U<2 zHqwEja2>w;55cVL21)@H-Gt!Rzquda79CHln_~C|95&8%W1D(!ef#^ru;-?CegA*# zd2C6-8`hWD$5F*`0NIizd=2{H97szDdQo}9iRs_I)^UZ&VDfOfHp*H8ta`QvT50Bd zHWI=V~&p{j5`&PLHJXfnX-N_7CiP(qO6ig7XnAUYw4eH2Z zeQP}@imki)zMe2m6kfMJjaV5?`Zx<$!)y}J1q)(-VHhES5q+6G+o@rMuoT3Y8&a}Q ze`c^_BZoFgWn|xKZ=E#NBLwzxAKrBmFg!Vqs&iAXqX{u$tJhJtjvQzOoI7j=oFM)W zUC=hIyUVfA@9pP5VZY;dJeyu}Q%~ObXz%+>!+Kt|o@9@S|9}X7Mo=5pG%UU+#yi1L z-KAw{Jb*kXUR(>p7`^(QD|8Ll1>=DS1j*Kuk{p}`? zNm~HIkd5y*N%B_h|4F4BzL*+`13bpmLjMEbb_ z!S4f2G`E2{ePD^=U$&t*BnwWH5R${l>;eUq7KT$o$Tkd8w+s>C(M9JWbl;pq8bl=| z33uZiov$;@Jc@q#UbS;Ox4%a3cWrgRew)SmoYSn{_9|vNI$;SvsqNf5uycbXZBUS- zavHPEFfs)!30jt3xioIrCZtx)<&9wseS|Eg*WC~*W>IWAYD`BhZ92BXA7hG7j516o^(QJtAUl% zy@H;?f-mIltmNe$@^)vR%2taGdR>{d_2!RUv*L{$@Ol?^pJot#3kVvr`p^-?08!bG zH6vr#S~Hhm)1v#As5Y>++S;$*tQQ@7@X}4{AYvz;5Hr{bbt5L}l!f-9k0f1r$Q}{C z-l+raZ_aM(JbGe9dz7u=3!nFi`I(Exd0Sr^zFg!K?bfB)!021 ze?fIRqVDoq$`7u{wmKZY4O{$bTRlj&B-rDqL%fDFLUhzuvJ(sDLIcqz74r9K6aU|v z43RQ*d_f2L*rPcKdZq2Bh9pQey!6yPj@;adP_yN6wzMxSzK`J9&AN7cxuw(k=-y%Y zy5C7g_?a=(=sij5s|lg6M#1RsR!oT%dj@?YIYah`M`mgDJ9dQoWF2Y-9aSu#)B% zv?ThIi(hJ`&l%8_KLAhn-vaRsWKBsh0={ku0uV4{p!9PKLdR2`)MQW0c}P6qF3@$L z)(do^Q#_8KN6J&hr8e#lNML?P^&0KM>0n^!TI*~@H7aIMLDHB(W^lQkIjQ27og&M5 zef#9m9TGF%JRZ!v?i}{u%wnL-7?R)yFnCB-rx8q`F7Wl(G3*Msag?3Wz>EfWquh}lcS9Sb?BWfZh!VD5l~V!YP#@@p(( zuQh(6WsJ+_YLrQ1vzdW~2?HyiXdTVVwRJqMEyFsPZr-yip3Dxdj9r3?O<{cvb7xo4 zXBt929jL&P5bI{;K<}w`Hi$&2zRq8hI`FB7m7_PAA@=3wNc7}2`Vw@o7i=UrHl)0b zOIac`0H~vNDbol-k!Aokmw0ArG_Gz^pHy0U=RvbtU7h`fwe=)H`V0H1o@|Ig-`8un z#CiBxX#8=xPENF`+}@AtY<*@e-%oi7v#Gzl*TCvuA)zVwe9Ld}+spXx`U`zfiLC~d z*jW~n65Ai5-(aV=V=kgwydMbY1kgs%hbovuz@d*`V&rmye3SJN3z|OYq=b05Yt#@L zh5iP37@QcJw8A|(|C~!^Cuim_zkIrWc04`3rBX`g78VQHtv#yo;8lyu+mhY_bAA5MZRN`j*#3@@t0ig z3J~+qk>g5@Xsq+%;o;Z2(I?Q9<4b>9KXp0o5_b2~7_C$FPQs9)Cb#v5^jr@UD8-)&LGXx*B|MVbxRJgtf=|hgpczwf<^zE4#AMU#&G)>#?rxL$oNjv$Hza zeX#vns+(W$IJ`c+)DO20h@?rfhuE(mO_ko?Pf?oVYqCvRfy!E1p(TQvs4r^4FP^O!tI-k#^hdg|;CjVb`_f0Z08D{j!_r34`O@^ZT zcAq|{PMtbcb+)R5aM2V*+n$88_%A3r?BIF4bE;aTVM(T)am@jfUSvIujkBy3uiYBY zX6G;2oH4diPpTLz2Fs+_i*H}B=PoFmT`;pWuPk0$7xg;q3p0)FiKhI#4#bmcEXge? z>DB%5MKe;QCu`{7{i|GY=4t}Y@%^f0IB~npm zN-IMM-dttw!ErMW*TA|B><2MBk+FBfV>6uPWXx)I^6Vo}Bl+bs(ekqkr)>G&iFU7= zilZrSdOJ72SD&)^!xN3~#OSVltXxKMj;0DWnZHb6qZi_O6d*oz4Do}E0fxoVQz_+u z;s4fLm&06YQv?BF_U@eCFHX;TAX`VX_T7><6aH^aH)MC4>)`EUAIK=?Rl~5e%G$!F z_p=Su!B0;jVR?9a4(~kupuVC_4C0?*HRx%Mf(cl4~Y;D2< z=1ugEoWRZrnw{n2GjNN7xxu(RWg2zBspc~#y?)21-A3Po?=}}4=kb24Ves%vSOJ{J zJA9f&Yf@CY1o@qnPSRSn4$MEe)z26PYw9(<*xF2pKBO`Oexw~E4_L0 z{M&qPcf{-d&EfTV&MDYq2F{{7b9{v|U#Glq%hPUeyhMJZ5ic(`qWcQQoD0zs z*sWWK(Dp`+o4s?qq}6E&1mrPdOYz*Jp>(ILFS~DoUu1M!_KPxQ{fyvxdpnAmsC4m> zMfHU~g*9_lGY>Jw*S4E$nf&6`ld|q}GVw@r5u@#(Cg9|6O9d-m-YKd7Avrk|GGxq${ zglVGJb3$L4)QZ`*UlDTH6P+bf5#xsHHv@S}-+1!{tak5H*b^1S4zJ&r22l=>F4m8Y zO2kOS96rxyhMVC_m3;z<=DYN}!?cR411X^Z2b~s9Tv$5(4 zj0>jfiNF|}=NKj4k)dJB>m;Y3P%z^=8k^~`TlR1YT2r+(Kf4zyBK_Z(+AHYXW_{dy zOdDjx(PRHj?_=-Wbc{x@N-z(uZ{fkF5C0oVh_woOY};>{$(#H2+Mq?KQJWA6tjm zUNY#wb$DnWS!8e_g04@;nS)MVd$U?(->Mjb=%1;JwXba-vGlQZT04b|I&i(Nno?Gw zZZas}MBSQDH^{2}w9!A+MEjRqA6u_$rxIfauGq=@iZg=b=#=YmBD$XIQ)*;b;g9=!}ZUfrUj@rr}uheppSqb1l*4bOu%Bcl+!5f%vgS*1_oLZ1nYF%$_%6 zmn8cZ2)8+ly*XIh9``tG9A1Ig+KUADmLDypsM?%hf z?)C`#MGwXEMqj4#xb5rq19W1~Gk?Y`ChyjYv^iq}e#^;=2?8{fHBV7d3K58I z*R1gWIZ$*4t5-VvgxqV@;(McS`~BFOdaFm6%d18%;9#jR@3R{U7p)=h5H{UZ0H z$s66qX=gX&@IQ~=)O%~j7 z1k!WmEQC|XoKy`}vaKFXMVrVKEUXN-!x3$6ld)NCseW z%p&!MwHtU8x3;Ectr6ORXoGqf2b7-QL2I{W$8evf_ITlJ`t(F}hpKf%a}Z;iXD>NE z=3(F^#q^WUkuejEfs(2cJpJhF6x)Cvcq<}z{!soMoDvbnqfN>N@%=WkGK4h-IVSmGiAM$j;q-a|33ONzedj5p_ zf10?pqV0^wVG!u(?o7VgW1g*OdeoXF>Ou@_MFdoxUJaUQdDLOI06}T z*+4`qjMv(n;ilr^mbj+XB;8oPf+h)Lg45Pm>-Q8lrYmB#IeCiBt%t!ymyX>>Ka)Sh zK2$_@Re2*gtarAQ0+uNWyo`BXUE`TvM!Bgu#8qI=FlHL~IEVQ8S-hlK54nr{Zhviq zy(Ad(*=$aCy1uZfn2MXjF0CfvwYh9T1f0uJlePC1x6%q{$dw!RxEs^4lhc71QKCv_w zMbgY_fiSkbUstgk(-Rx6nzpD$zEOerW1$VqU8}}+OFz9PI9e4}Hp@go489+Q8*!8n zu--VzG~vX^+&XV86YyGwUZ(M4S1Ptg5KH=KQaI~RaWLyk=7!2f&+zD4E}dUQ_e~CF z9pXsVqxBOJJC=>@g6Ml?5{QXOvTwtI0p6OnLK z90^ersp<{mhwdS`QutREC?i~UZ`iP#7H*)}s8mNjdR`WPaEUqsy6+x~!<*%JzKTG! zQMbbllg!9hVyQ;QmPFg+d^x{VRT%;Zr2@$FZn|sq!wt%1A6!DC8?20xGccAL=s^Qx ztY^Al4eQ7q%%Vcv!+*8z5_b6iZ-9ye(m*%D_?BcUA|;u(*OTv~ujBjJhS9_6Ya4Fe zU~q{L_e+$N&C`Ln7*M^4DuOT)7~+xYvf1V2JVSvp?O&hu@#Vf1gKcX1A*%^Nn* zBOhIaY%NTUTz#Uk4Kuesm2!T~#ny+CaB34&cXBx>$&E;mE_nAgDbM9`K|F{toRnv&PubR8xZxhU zd$gNdc)Srly2xzjtWHCDF3e0vxn3H_fAOkb37&DH6oo@F% z=DSO|j5+3`=Qp5vIY;IhXh|zaC)(7dYRrwu5nFs)`MMGla5Ln zW!PZmM+>tUa(gn5=x(Rif%BJk^nDfUnBy3NO(JCmtCR)ae*5k9>*>J_8^9&%$Y?W5 zqPLmvvbkm3kw9CfC_7uSIVR;6GFT2Q0w&=W8~q!DLC3ElTY3aJen;F#H`2FY?K#?T z`U=Q^PNf`FoCB1w<%+Ey<&CEt zyB;YKk%((#)~0|;GIGPQ7hPng!O8}Di2{9%K^gi7YHe_(QE9yT-~#m&Gi8YG+iyyK z^}%`SX;z-JZT~6pY9h~=cyT`|QvtmB;3D;8la6B7e$(O22N$Y4P1*>SAXC*Q6~G%a zKj~u{PEMylx|)3vazOgVQ=%8WZ>0oR2<*z2l;w&5bP2z^@=9S7#bS|ck(WU>B*ppS zM)8qoYb$;9(HF0}YWEda?7r->-4}?D)WZ&2zh3NCXU{$<9)Iygagv%44K@C!8t@-q ztXuN|cv*)%4iSI>u`#RHTnI_S#;s4Srv^1$iK!6uAf!OYRT?D5diA`sms21mTaZNx zzA@y;ECqppW^&4y@ky&R9&_H~A7Ro2-$FRVjHeBRqo^#EYDmY8UPH$Fh@QsQB4c_F zD3~eDvXRpqGg~eO_N(z9hQFpLGZDo@vld203OFJbo=~n-U2u&>5_{dXBqAm%64s2( zW(<=&L&bx zjRX)}NYQN`pN_~`nu7R10gtyl8Yy#oVoq$xQ5`l#S8N`KBj)jy$MS2vUN7*sE2`ZV z3#dvkf)E|DCt&xMmg;Urb4XRm*Mm;Q=Ws>b4rftVap(n3?=(e2Rd6l_+cxyk7u}J# zCx+;;I345GgI-_0+Z}U<;oXC$Kw**+DB=j{4zKQVI$~~jzAu<#x9fH%GR+CWSi_M0 zHFwCSz)r{%#A@?7^pM@@3|IIAeuu*ma=YNJ z41e}0q5|`SP^cl_oA1_eT*svq#Qk1X@fHPxRj~SXSo@3QV!07Az8*V%ju3<5Qt_e4 zwB?_1#@VNze)g%Sp1pJD+1tg3>ej72J>qP2tu|NtHG4*%itSmMTI@B>n^;T6Mj(C; z-kV@qJho+%XP<+wCO^iuAZBnpMVGKu>HII&O0#4UAy`^-6}*=tL4&NZfycr9zJ0j7 z3SD5Lr!lv35wT{Yzm0dm3BI=8G@x@%VtMl$tm>K_c04&B=`?!4Dbk@Z)51ED1jq4q zoTDQ7T>^VKB)F6N16majA!q3c0c#AkP))B0SU z=mY2k0rVa8Z<|e%SUORpZZqnuNDaH`CLS%3Dk={4M5PtfQ{`R<6C4**6;qClV$$BV=U za6ieF*f+6442auAx-EY|bRT_m_r{IghaJ|vQrxC4TC`w+=vFi6;-8&@?=iPS4TxRr zqq3?R*fd~OQ-Fh0O`)BP7MY?IEHy`RS{>F~1A7a|iu`7bJ`JJIv-So{OT1*sT?(Vl zm=!@Mfb>Qdt<=EV62ZcVB+fr$Df9`Yh*HP}>{vtvQqQLdKJcmdZE)xj-hj{N4b%qE zbTG!jV32y5I@O8wNzD<`AtGI%K17op8yx~Rjs+R=VJ{gLy&PU!Ff(_K2F7ta5)Sxb z4q&foFpMa>iqn<{ZYG-o7IHZpq`W;?eD84!?uj znKaGi%JGL)44YmpbGgdO;O#`Zxnv#xw;Q;SYV$d4PUsTNjp0<;N$5ffJ_h=ixw!;& zE5szGa?p1Sp{i+NPdcZ{A1LvC$EM*BqGHqC5P1a<^IAc*s?-$d;F3Vd>yBWWgjw0+ z^n1VKE((UHM};yr27cHGTVPl`D_#|swJrJ6pI&|8g+Kg3ysAF?>@!zh`OFnpJahTw z&y0+Gw!8b84I8>vt=hO`$;K}6S+%2M<1_HMd-wA%J@?9Uk5|4@`FP1IC65=qQuMg( z73WJYDX*vynEnr+!vFU8XPOav*bk-^G5&w+oxx`iX00-V029mrdOZZ5rP>Q9R)D4t zYd*zL^`_8dc2Et&qXuk}Y-&{ui-T>8S=7u10`$JgMTSiQeloKTneUj>z^$VJaH!eohO7iQk;Q*=Zhf>8;T%FH{;)t;u!op68{9=sN(N?*vMdhHka`q zh-GjOxDR~RfK~i5*0F5-?s1XWLxoY{ENZo5b2BsVxSX`iX{0y4X`YE!rnm(!8dfeC znb*q9g38!R@R?R}M4v;}5FII7Rd6mN;1z3%Chqw^{wejIag4Sm5WN=7wmK zY%)Tt*)%(*KKwaeh(M^gfCdBE;nVHlSnx>D6$A@o?Uag~d4XB@S`E0Ma*6yYhtr17 zeGc+_O7g*dN`6Ja>yCmUGHm@i3L{QujZH1Zk}EKQoU}m|z*^xQEDq=i*wE62X>PkO zicWyZZdF5nQ9Lg6PZ$M6kol?-wc!Xk%pVCG!3mM$g3@A5brq&_=l=G_jP4Wa=%6)?PjVpmCby2CaM8n7$b zpoJxUe0AVC9(2_l-J@x&!Jub-PETnhI;Xu#3Fi4y2Mf9 zc8uY%P5E{;rF|MkhOyefylV^%=cuy@14jO7Tq`s9&AowTwIRbz8^Ibls?2D%02p!Y)yC6XjEmpdB>!xD{|B^a4hVxUs>UMM}HPjz)s5 zs)cMY1ig^;Y$<472kc-lk<@HFu0H^oZf`lfwVOAOW@p_3TfCA75?25ZM0@E6Y4g}^H zY9LeVU{{pmjKPrjg?N|eAxqyi=OIC6v>2;KpETtai^PfXcnCv}N;I)gFOV@~QMwgx zTWvbG5Sx2w8CLF4deLGSoWUOTc_X z{|&g@!IeB90O>VC=fPv}3R+!9giwNmKh5F9a0vz}a}f9dLk}AvDViUDM5QcxFxs*m zxv&#%+AwH0EC@W~6cCP(JUqSN$CjgTi3dXnMRlUnvOK^Iw$bPzkEbdpGR^OW!2tWh zsRtBw^fVL+xfOK9^V4(fewQQaa^-qFIp7{1;PGlY$#b-z6Ehce5Eb^kNCd5|*vYO} zL-rtFpKjB&(NUWNXhW0f!chYln6l3!OpQgMS++r=y15WYcSD3J&@b&f-!{(c)jeu%n7btCi}2Q z`wE_m#!AY0(CF}l3I&=~hiZ0^V~Ph$NWd6X#s|!-2rb@$1oJ6-j>`EhwgiAlW6gUE z*Nx9~^TUrDvu_0Yu-kmjcz$ZGJ>YUgobEiU#kfuixnV!Dl5_-hY|Ml|A; z<4a&GLVVcuu)`I=U=jpZ78hb>2n=C&1TlXCa)B|?`%@`yPvm0{!LY*U*rusodwdav zb%=Jf03vFGl2Z_phGF2LWstvtgQh#^mzXVp{`{q`JAw{lbP6m&F6n|iTf2*g;7)f4 zW#f}D%m5W*AiHwqm0$wMpouqd(+M5Di(|s^NLFAZo5G39A?%q159_)|88S^UtZ_B- zFi{rCRCAGHnl^faVhk@$?V(#5rd5gQlRAA7RT)E32oS{>DzG@1y3-dZe~07^1iU`z zx{6${*XM%UX&N=f! zaV92&k66F{@b&ADXljaA9dX3rXVBqT^va1-j@oke1!tYFoT*)K=9#uFJnS>aeG?{5@}Fw++aJvN4+tmL z@S5%SkU4yJ{pd4+91Nl$s|g!hBN#tm?nT3v1`N1d^nIuq%m}$L%5vBpn1>8u?1c|u zPN^{7+Kr*oB2@`X^e<$MNlyv0N>Ptj6gOIvZ9@DxSj@AfrO>mO81*^b9_er>n34)Q zeI>z?g8XUj9LziMh|%wMSHa(~FOcVSL)0OaLqg*E?C=>U-)dOAxFL~%ESrti%*Uwa za&af?-dT4Vx;F%|lfaU{4?cb|cY}UWR#j$ngvnH6!kK0h55B?wtaw4~$#dl_#kd(D zugV&0Am_?_N;Sa`O{P^dhXyP$Gpx!R(IzOvn6Dh~Q?2S$dbB`!8)l=|jSy{+{SI>Q z|LwXD)6IrN!&p+mpaI6O)9LhL!rf4)n#TiG;j?4XT?x3|xn6%E&+lMv4!Re*WZj}U z={!u^Ls~)IC=wIPtXFbE2oTO%6%B)o?9ofmVX*Vn4OKYD9&kF*+S~)3FtAKjxEaF} z7HY!_oXuf!35KCFhM@p?br@ex4NVh*Jn%xAK@>nlseY%sDhD&* zzKSqjp!plXFPP9_JlNicF#z)qh-1<+=)jyN)Hqw&FfOGpH2ORRqwbI)e3@US62EBs zQ(W{Nk{R05urWt^XlP~6(H@$ud5+}&rDaCJH2K5uOFY>&^IhsjbN^P`8b#)g=ShTLI?9fpI;?hLv8UYJKPYcNMA zb-&w{>-8ZXCyCwSM|3Y%MzKYqO+upaI%_HHw>_47h_u?;b&PNY-8WFvbU5F1q;jk00bD{h2h&_cZf4q4s z6T*#Qx#B72F>%@#X)Co#PQ;;+@fn{JM(B75HuKbb4c&)H+ogUi#Ar5`9yreJcAvh| z4GTXf9?9Wa%Hn6eHYi)eayilg-qRdM()~{bUHSz(3l-_nf3Dg6x8EF%j*iXyjP7vT z&M6AUa?kaFrSx4nb#CPRpH906lZzNN@nBLxuMZN4kHONZ{V{?NVxB+)Cjj@0YW@)0=94^1Brol^8H{IP>>vTKp zjo7@U)>P&O0@J;@URO~lCf|C-LRNDz4+U3Lya$!{ zxtO!dtnN*e=gLf#d8`gP0ZJb+O6b{8FsG}wz9V<~n#1b4>SCLwS67tjPV$t8=hHJ) zYYWS(rcZBMbNVT{vySSZl?xZH%xMTyEOsvFc&qp`-6HS9iYj)H#o-rCF&r%$CBt*R zakdZwH_YY-FaXVPWSm{ACo^=*%uuecAm8rQB@eS|eZk<|svA-iNYGkeyxN-s(S&*6 zaJ1I?O0H*wc1v$l$8>5lRUngx8jKx1w(%w~GT0xaF8;S!yI1PzL zdY;N5|kcqaWr6WsOnsC z1f5n%G3J@~Lp)v}g&%gTZ2VbYURJuDH;F+<|;4{q1vZqYK+=6ROf)(-;fimx!Pb z1`E3|gmt@I?pOe`9&mV!zIG;B{kNbOpSN|ksYM8Nn%y=Iw+79iLzdCG;X#;Yqm%Ij zAtOq^jn~dD4SI@}6vo1Bg*D!Q|E4uZ*t)CB7Qs}V9xbb(i_2T8;3T~$l`o6@$%5wG zqRxuDj#^A*4I6AOXF(BD>GNo{2f=$$#=*|}YI)L#x5b29a3&Ub(S$~fB6a5-_7Gl0)22;NTaiufZ!I`Cg zQ*(rS)p%G$G=;^n>|PCA9D$g``JpKLT4Rxk3dgFV^y@aC9iAhn&70d$UlH~On`-AT zsB1oIX=ywf^;WHpcxvOVc5r68Hi0EQ?{9rkGpqLaLxAJ(aDMt9fFtB!;g z)YY^~d%#A{s&+2rVwCa(orqn*d>R6sg;@cT7CVBQ=!v}0n^+9Z_-qd4$F;QD9dfzt zb%X(=*hSOn0a+$Ih@665?0EuVeDT=a#m)$3Giq*%q^p`tR^vJPBt205JM`j;KZddW zfO7s2g;Tfi@2ctD8XVb~=5v3^hfrt*evbz;VkCYkzDnmwKCg=%*7=xWV=ZB{j3F*z zT(NBAQzcmK0>`0OL84byVd)gyO^XVm(E?23z#4SvMNJqVc%ztWTD2C{_eYT*RmY%O(aIDi;%$rsaOr0{MU#IWa$u>#9_`0U{Mzo=?o8*vpyJQVX{DKijvRr_FQt8k4L#cmb( zS4vEB46jZD_; znkd;@v$J0jgD^&i$BxE-QnP=qYHdM9RrNGOvCllJa}UK13f($(4c$V+n7;&tu!O)A zvVj@Kbvi_i`5(A!D!q;cWgb&tc&FR^S>@hh==K_W1bce0l>o18p-K9E?923X8Zz~} z8#-WIzuTCh4gDTLD`gdYb}Qn(`n_tQso#C-WcA)`X!p)avebJiWwm=O$I$L$U!uoR z{v5WbX5nN!hd9>ROP5-mwW#1@atb})WU3_SNmBwJyp|8y$dmsuIzG9FiVp;%-jH-c z!DEh4YLgUvafzwmSEB8P#&*%mv=cE140(eX@y3ZtRu>1O+F6HwtZv6Pb5`z4?Gw8F zggMyrqSzecx*et{lsk0$*j1qEiKdiJ!gGlmyO|9sZF%eb=T&=A;ej=KD-^rE<3M^H zxc!z+hFq>@O68!J*~GLgcJ;DKn?kwIl~ZYVzmK(hbgrr0tJ~`0$|U{XZm4&XMX5Zc z$d}AF^!wfM+PM{bYIwBUgW$g~Yj`*B_~uTRY)06XJr#V6_4_3g>b>^(GCJSE+P$uN zP4#u*h>vyq*wyrFTqOa&Wyp<(AtvO%C7_tfa7Lf7`u=k*KLHa9gU7e-?x8K`r` z0d-z6jkS4gSw-AX=DG2_pFx)=8(Ei6(;6^m0l^Gap65OGr&z)(4g?KFUQ`HPzHsbC zdXfUbZErnZF|{7&o-~yr$NZL|$wzAE)kF;;no zS)I=?)M^nOs}VehqZK#g(U zL$!1MhH*DpwTIkTG6?@JXsY(_RQo*M=|1QAKDRH|Q0&m_V;ku_x+$yIF^YgL&1wfI z(*x;sZ?4Nw?E3!nI$iH7448_&X8O2ZSHn(Pex7>4F>dc9y>8)R>2;jI-=AJ@Od5)v zXLt^**FEmN)jD0zYCR8&(nnpuYP})s@?%U9!{Q8-`kZxpD0L|^m{ak~`RIr1#q_r5 ziWOapa{c~_t_p=C=!y1f#kE?&nBCfC>F4=kU=Gq{j7m@bY@*RPhMbjMNaA`egkLf3@00rD%@dR`m zqA%b{vMLk|MjIjp4sQtB+ZNaJi$d!{-lod37Mk^ynM$UlvZ-jePR@_i`KX|&pgvex zQIIIdwt$+5JsS4FEm_na#%ftrxIVYKgsQ6o`A$p{y2=6#wwChPg7SEARm=40S2t4P z>S@)@)de&A7lC6t5sO5T>oLxn3Eo#iIN8f55X=o0#%ZlAV_73V!#p(4(sJdE;{>oG z@sG)aAvQGyn(~ShSikWnO7m(0njec2HXOhzO^{Yuj77XirZ`^jjTJX`RJXg5C1F=- z%lyKM){IX@p*M6iwg4Q%saAijc;DM zFgka6cWLd0#oYJu;1!|)yKIZm<^^rOs;Y)q%clUIc{vA2rHi@@C+ zIC6clO9b;uJgb1NsvA=V=%T1!5mBeB!u6R*zAYM_UOjtG9q*d5)z6+iy~Y_XjucF* zXsxd=k9!00vWEJ(fsniAGg^>>ua(s}N@o|(t*NQweImBH>gw6C+QiKAVAtBJ+V-+| zV=||#qain07@GeV)PqnNKAVyj$FhgZjF?lSZC!g?T|H?ttE=nlTFWW|RagZLxMzo@FFGTyaeiBk*KIE^oS#f} zIYV{1)7s`ItCr}Ln{fHVjwrTH)zx+tH$|yF(pFnnM>VZjFRiWa?5M8`6(=0wfU9iL zig}fRNbbCJsuO!-tE(Eix{`syqG(q#J+HB8-uez6OOO71N2oN^NxPRxbq3`+R3NvN2h%H5&eNt9<2)IMDOBb_}-kN zV0kj}#(ti2zxyOkdSi1NkE#_rwpAVa`!`bntb5?UgGyv(b1>N*xWGdx_D=!0p2U{% zLx2BX3h*}k1O6RUA~P5LfSDai@Gnw;y9PeR32JO5I`sGNr2uw09Qf~`5}DZ?Om+t@ z@KA~=D8StZkA-j_BJvdE`QJS{C>B4cL?#}Gn&^Mm9v}1dct7yqfa0OQ|JxKe)I^_H z`*0UQ=0afO@1ei{;}kg5M4wm#jrRi|cC#M(`}a}++sF_6cTkDUYz{TifywzVrr-{S zPceDQD<_Bk{;d?i(cA<79aN$NXLBgU|B3?K50HTn0nh&`pF^Rf(Da}ZnVG|B z!lA!Uh61cckh2g$4;)e)`un$1z;iG(J*Y$`TG#`B=ZP>IZJ4ko(;7kDVe6cpfYfX6~a zyzFY`(BJ=M3LI*pPpoxV(I9gnqKG_y=XZ}#6sTzQobC;alcZ+ts@9eZOeAp4cC;x__d7+)CQDVL4K@$un!|2^4nJ?D>% zKX`mUOq>Z2li+>a&j$1X767^cI{+hqIe@Kz69EeWYXSX$G++&&3UC;p9Ki231KI)W z0sL(-U^#%l-41vfa2o(o`;2tWxV9i-5#joMz`cNNfMWo^0(1lTo1+0M0ha-e0&KE= zb9oy80|3Tj3E=mDUjlXl7;nb+3P2EW9f0%ZEC0S9!1d$&`S}rm6@ZfgjN7pQ{`OSB zd4OjCMF39Ab?N~u1Dpvs2`~)cycq9xz~O-708G!bQBS7(IRM7-cmUJq$AJ3)oQ`qf zG=Bnc8BKr=0MoV?Fb}}rF-@ldS^;GMe!dF8-!RMotlke4;yKf5GTedR-v;cmfa|t5 zaJ?o2x4{Vj<{hR1*O8&qf{nN`E=)ge2j&%q^#IPBpD}Qn?7Qrh(_|r=U-ruN=5n}x z-1ZF2e+*2!tpKJ!)8G;S<93}1V`I4b0bCD$4?J)d@i3tPh5#jiv+(RaTyp?Fz&-bm zhXDLt8-TyN9nVK`MH?G=I&lwvAA1{D2F8P7@;(2~pY%NYj`L$0@U_nB3tSfS`x?Np zfa@(d99O36DS%S}{QhD#qh z>$(|Nt_#}TXbZk_JMxv=fcc^qz_@c?=eA`2;C$Tx<_G30=69|a+RVVe8dt8*LIC5< z^x;0}18|<)x0%*4s~r9=17N(FMo5P^T811k@L+myU8Qy9^0-YH|C0c_04%@m2XK8D zxa_5Xvj7(WxZP?2T=o_Kmw!B9E}#g&bzz!veHpl(+!owE4nP1ny^kxWYr;L#iOUuM z&WFEU58!@#K7eU-4uIcJ0^+)Mn9n#5BOiXhdr~^S-}`qqj|#kF8fM#se>1Mz0gPJ< zAPwO9F%DHIgWHm6#$_{IxL!=7M(fIQhWUuwzzg6yR{|CRIB$N>bUGF=AHeN_d<>b( zWp)F&jrq#?Fb%jIPG1Tb1n|2gfZK%If@KP~+tC2vD2@dD5Wr>fcigs&Lm7bIy8z5T z%y$|<2k?6j0O<`}n66xY)C8m60{3Y5u{Ut#`=ABcKC<_f-_HX~^*sA6U->=LH%sU2 zGk$&wfXiYYWqc-o_etI}o!bESTJQy2x&2lGxXsQ7Fz;}iG5;|B+-}@=Sx%e@$iB~B z`5mWOU|qAnyYQR&hwFI+fb-|FCc_H+-WwpxjrQN)m2o>3P!HgCWIpA*`I-e~(sQoU z6#(W>=DEuNT(9#i=*M+3T!r5Z%zJ$0_R9j-GYi~KTt_auY7%f6S>SRQn3fEiC&5X$ z&jRX7|%H$F8?^d_DL|A?ziJP_czYtX#n>dmY>{Kw*t6sF9U#| z(MK-D{q=zB0ILAY0GxKR4C3E=!`pcF9RSmw07U?9@4eF<;J0M_I88Bt<8@Fw$Z&Y{Kt{Frc^}HC_#P0K<#~;07Vo^Wpd& zyE|+b3W31SLi;AdjbT+ozgP%t3K#a%g>aPO^eE0!J72=-IppC^0`RRz0uWimi-g`& z0dEQ6Lr6;B!`MBDbb)KJYXs$nfLG{6tQaEVNcd%}nB0unVtfjxub8AwL;Y8 z0-h0~z5`w@{D7y0NSp-tg%FL)0mv^I1mIa}0C0m4X6%nAc87h*QboekXPxB?oJ_E0d4rc4P~}B3DE&OJMq2? zG@4f|#QfPpEa(zqA@E*^x-LSx#oL8gvJwDVEKLGX?y@6=Sgrz)?~0{DtjrN&6@IS* z&a00XVokjeYms*CyF#q{g%In{6@ndPY(wR)`ah7NWmgh;5+7Hsn8m_XE!gF_-`h0A3SfJLqsCa6J)aorrfka)cP(Da1&v z5GP$B#K|2(>^w<`Q&7gKU4W~FI1TSk2Y-C(9Kb_DoS6?e3-FQe%>euBInOad;4xI;M);n`1j0^Swk;j4srqzQ1V5I;k{kDV&SXAbHB?o|S zUqjm0P>;VNkG~EJ@p>BYun=zmzc=3!;=fS;w^j@BH+=tgP>BEDB*Z&Qh4?$t{SWH* zk0{_*Lc9z5y^Hkkp}y~fcJHIU?<4>B9|gQ4#0Mzn1El%z79l?B5@HnJkK+C4i->=V ze8y1kv6nI9G#hZUAcCf$vj9I31YbX-_5$7#WP44Jwj6MyARTG+3kAVx71=Rc<;VqG zA;?(_xJHmG0eD)Fdm-Q+K_2+M^E@HQJ1of80(ef4|7t-2t)To(fENW7+$pHA9Ko)TXK@<<-O6Z-w{-X zYx$*uDu6@f9fGP*=CoacrX&CA`GBVc)!u}hK zI%ggg)C4@5PZiYiw4fRJfRhBxYy!L~Xx0saW^WWUCn{*J1mL??q-(oZP&>Zw08KjZ zyK|SIt}Xy@op-sQ`Ch;|f)*45Q0~I@fcFJ0!gbM41TDsOF@7(3SkTh70JOuhD+Mi| zD`-Wzpq0R5C1}4A&sQPu)u_jsrGnN1mvv#lHwCRn+V#NyFgF0SI2`3~1dfpFbOdO3 z#7lyXJYCRHNPiUQbTslh2G5Q~UfuY%`&WWCf&QCN&&{AKWIJuawMPK@0k;6aL&voM zaDN=W-C7MeUQn-7P#?}{iA}mohxVnbQ!D%+%9PQ#ez;mdkv`o zl)2*uLBq!i8Ubxao)&Zx>UT2IpNwyJUMuL7#enApow{AnX-IP#Xmt8cL7$2OP|q{A z2s-mlL1%#m=Lo=Cg3e6~Ixkny`Ns-^?4}Fx{6gS$5pcN}zc29vejw;lTY6pv?ccOwf&M1$}j; zpqr4_O>YVM8t8cQNrJwP-?yw5^odU}mlr^dr>gN5=s`W5{ZHpjgn4@$AR91AzNaY5^Amo)Gk42jE>n525UbUKjLJ zy!+|Bf*xK9z_W)(1wDegJaV(3N27rA0lyUlIZi)Axj%bY&|^*j@O%tuA3qFm6W}QT z==elAU^!qX0Q7m{ApmfGG8cfdpFAFL1ps9}`I4YtyeR0`sQYh_=9zZ{J$JOA=NAfk z5qZCKi=aP$DCm_(1^os2ymr5!ze>Q%f?fxHZ`1=&#+!uz>`>8&u}Y5-{ZH>7!c zE#Mx&+k*akBLLsNbB>_D+X1HokpKVuM9@E00zi*<@$6lc_ug58-p>b|3wTV>2T8yW z1bw((&_`zo8U>DHe!)>RBt-%DWA+O4f~Bugv2Y9ilg9s@d_!w+&#Mzr@)}ou1)XKx z6QT~!w(ccj5HGgw6+B;M-K)4i#=5r&7ku<{ei%mJAE<5I>$nGY#=Qggz}~ob;oFO? zdpGW{!rBL^IC+FGZ?f)58GzGbMdd!TsDw!Y!s+TxC(!NC)X z7Y>f>=&3DU(AVGJH?Xy~`0y30m(&)oThhLAX{setyl$Xx^Wc`A)jeBB`n!kBhjrG& zJ(IMLY%NYU8YP)8tp6Kjo_zAj_1)Y1kz@Vl!EJl~5}k+uyqhjtV#L$fhIGS7$L~7uW)S~Q!2Lp8N5l@%W4u{_RQ>qZhp)C8 zPYy@K-PK}=ala1Nc0`w03cs)|h{anh)*)RVB1#UTv>v4E!B->rz8fV>PFc5C%E|Bc z&ZQkWY(?Hl)McVhlfT&WexjZy3;tJ+(zgQ#6UTZ3yKTms{k=1Lgc!RJSY~BkL;oI-CxVaW$Yz9ZGC4D4#@`Y0#w!F*sV_nSCaFuFZyDVil3) zH1r?4aKM?T3;oaoZuh}ESpcp*L+~6M5m7`v$q{jp3xDlEJq8iM1Ne3R$hx5tVfI~tW=4O@I`tgViq2a{&_4y zvv628o$LhX?1;bTMlU>%Jcu3Y70-}Q+(mx)NWD<(LcE5Z6r_+i9xZzU_@*Cid_AI! zZbzH$K-&z9lR(W=!F#8PPl?khjM(x~iivx~MTpw7Mf?n0unAN@4qS1Acnod%Iq=uCcWMu&^*#9OqHj-Vsy zC_0*sp<}6=HqmCZffqK!dbhyiO<55bdC08ljWuWZDUTxNnL# z#B1U&;;(cnokpkAr|1kilg^^E=^XkroeK}F=hFprAzefl(`aBjYkx<{>Urfh?3ovRIbLQduU;WreJi zRdSk~E~{mYtVQg`did{5$VQozDVdfT*(94~i<}{6%2{%@M6gELD%)hc?2w(ZOU{$? zHaQ>%<#u_Z9FjZaupE&m$&=+yd5Sz$o+eM1pORV>{#gD*J}4iOKa~&5N93dO zXYw)mxO_rBDW8%*m%os|l)sX{mQTyy$luD}$!Fy6<+Jh+@;UiO`Mi8Vz9|1BUy^^8 zFUwcttMV`MHThThx_m>vi8ekebZ zqjF4P@hTBi3{jUj4m~18IuJI?g}Bik1;J+(zY<=~TLudCGicfwE9pq%2mJC`*-P%5r6evQk-Ps~;HY@Aq!+8R{F{ zvbkqqxM!$mi#~rTEQR)7^E%JGCYySlE4KFxtbu*d-{b1+AKcMn-W!j*21hn!ADj2V z9oxG%_Z%}YIB?9Sp`Pv&@EtNtB-$H$^{&3|ZG!__`K1g@l8KZ>npC3KzP109 z?Y)hSEoK4fUdQ2GeW2lvz8(BYW75bPm2U4EzULD`}>C14EOc-sPp>)xp>>l?6l_3hZq z%%RU4Fs@2x_jaXoWV_bY!#1R{cyQR(-oL%KTU*w%ZBx&Xx@Zuszq)r&0Uv1i2#IVv zjAE7p2W9z+)#{d^!R^{=q#N#WtR3ne*s&c2*cNs4bZ>Jk80y~A(=~YVfNtEa+wNF3 z(!FKX$l!2~y0m-ScKe$C?j5}y-9xw;+}?v5&Z%+7u+}xWt#4pZn?E?Tt$SEqI=J}+ zkHL!T2DbDJZR#FUmJV*!=k4ra9H9qPit!C`ITV1IwlkZZ@_al^;-f@^vP>}$FQww&CzxmV|JK^SFa z_sKS<$1&>Gp5Yzp*1_RHb-4S49+eZ=)||-y=i8*Vrn7r!a6sE(T(W$V%-*E4H;L>` zmeCq#WS?Z1XVZ;FC&AV1B^=|;1&q?6Wn zNuzTE59|A+^?lO%K52cQG{s6fY2}l&>Xo$WmCV-5%0FY_m$C9sSoO$cuU0u3tDKBg zejagnBVb!z4!m~45o>kvYtK3ejT(rJX zk4~#xR?SR@POIEbtK3ej+)k_9POILXR=J&4x$RlHTF=|F&*x=TdZI};bo-2E>)K*n zv+^^M6|IS^+D@b_(VEDL-$XOCeq$q}n#`D}B(uB))SZSlH4GLzYnAog13eBytMHw+ zZaZJ>tX%j8xg?uRF^Oxk*TGg#e-G4#$Iz!)wdGl{t!Ha@_Lqy*g=KFUTFX#}PJU{B zZ|JS1YmLhS^D=LhyQ6zYPc{pWsgzfoWN1Yr6KI{DVMA-N(&o%otTtX43e;n0-|Xi; ztMu$|7ckD=drcg&Kh3-c`v(U+Tu2%Ub zcjLEJzRBJAZIy3wH-1~?cUt9l&hNE%4sP4l%|?$&X&a2BlX`51-R$H?rrB&Wn9#vZ zykqm=P>;5(do#=nTgOn(Nj-YI`AhHKW<1q~Oxt6%d1;4ve^QUuZCv#B!L5S>Jtyeh z=GE1?dAtzU=81b}=N6bbn^}rGH;>rhY6KtJrwzRlXwZZ>J%OD84JmKp?6mjV&3-+bRc`F+3n zzMtPOH{UOx{C>IdUK=o9!HOTJlr~_}dY~It`!Fo|-X3M%z*eOP1Hu(n6;~Kl^sML| z8Q9uAG_tL~dt_K2v|bLHF9#>T)K;4Xt)5)akojzA^0PI@GuN6)R9Z9n{SNc}j!Ey) z1ICeeubuQmTWbn!Zo8Q9y_4PgN6SvR>3`Z|jlN6arq ztS?5)FGh?nM)vq(#QegwVFF#($&>C6pLBo9#J#rBsHJn`IGbswnomw0e`13W-MYhd z9EdpFH#mTrDD4A-th&+(D4Xu%`uY(4HJvf;5{YDj2dTWGV92&aqbaKrrag}5rtE7p zEudthX#piu2~&op5*@wTnvqRAdWP+5Mqtn3hV#obnX)mHF~83=nX)m{Wagh~GG%Y3 z$&`JWCQ~+NnoQZ5X)-Jcm~``cotrSX(KC#ZTdxh15g74q?jPA?>+R`=8Mwuqf-uT# zvA%7w%4jj`lxZ>LbEd_@sm02>#jHc7#loeo;H~#1fHAvrpYp2o6IQ_JfGj|M0;YUfaeFeYUxCx zS6wsQZCI^|W>XI(n$3D7n$3D8n$3D9noYbC%_cn(%~snsTW#BH()#~Zb?!I_!$1%< zD1nHAIxV%EDUg?*3*-vvC{l4e5O-t9z9N(>ul#vCh3&CqMb1l+>sRFZ6*(_Oa^MQb zN?~0137&$l*z=1z2>zlTx-l-?1$V(+oD~Fr!M~xMhNc?YXlO}!M)HNu{V`1QbGBNR zw=I&x&r+=QV;AjeU&OzbmBCSGf8=6Me+^ literal 0 HcmV?d00001