From f4b16f809185e021916b33fa61a0f6d1a05c7e61 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 6 Jan 2019 00:10:44 +0100 Subject: [PATCH 1/4] Add the --format option to otp set to select the secret format This patch introduces the -f, --format options for the otp set subcommand to specify the format of the OTP secret. Previously, the default format as hex and ASCII format could be selected using the --ascii option. The new --format option takes the argument hex or ascii, defaulting to hex, and replaces the --ascii option. This patch does not remove the --ascii option but marks it as deprecated. It may not be set together with --format, and a warning is printed if it is set. It should be deleted with the next minor release. This patch prepares the addition of a new format, base32. --- nitrocli/CHANGELOG.md | 2 ++ nitrocli/doc/nitrocli.1 | 20 ++++++++------ nitrocli/doc/nitrocli.1.pdf | Bin 14045 -> 32165 bytes nitrocli/src/args.rs | 53 ++++++++++++++++++++++++++++++++++-- nitrocli/src/commands.rs | 11 ++++---- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/nitrocli/CHANGELOG.md b/nitrocli/CHANGELOG.md index de5980ef..f710b238 100644 --- a/nitrocli/CHANGELOG.md +++ b/nitrocli/CHANGELOG.md @@ -6,6 +6,8 @@ Unreleased level - Added the `-m` and `--model` options to restrict connections to a device model +- Added the `-f` and `--format` options for the `otp set` subcommand to choose + the secret format, deprecating the `--ascii` option - Adjust release build compile options to optimize binary for size - Bumped `nitrokey` dependency to `0.2.3` - Bumped `rand` dependency to `0.6.1` diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1 index a6bb0c63..9ad0ff4b 100644 --- a/nitrocli/doc/nitrocli.1 +++ b/nitrocli/doc/nitrocli.1 @@ -82,15 +82,19 @@ This command might require the user PIN (see the Configuration section). \fBnitrocli otp set \fIslot name secret \ \fR[\fB\-a\fR|\fB\-\-algorithm \fIalgorithm\fR] \ [\fB\-d\fR|\fB\-\-digits \fIdigits\fR] [\fB\-c\fR|\fB\-\-counter \fIcounter\fR] \ -[\fB\-t\fR|\fB\-\-time-window \fItime window\fR] [\fB\-\-ascii\fR] +[\fB\-t\fR|\fB\-\-time-window \fItime window\fR] \ +[\fB-f\fR|\fB\-\-format ascii\fR|\fBbase32\fR] Configure a one-time password slot. \fIslot\fR is the number of the slot to configure. \fIname\fR is the name of the slot (may not be empty). \fIsecret\fR is the secret value to store in that slot. -If \fB\-\-ascii\fR is set, each character of the given secret is interpreted as -the ASCII code of one byte. -Otherwise, every two characters are interpreted as the hexadecimal value of one -byte. + +The \fB\-\-format\fR option specifies the format of the secret. +If it is set to \fBascii\fR, each character of the given secret is interpreted +as the ASCII code of one byte. +If it is set to \fBhex\fR, every two characters are interpreted as the +hexadecimal value of one byte. +The default value is \fBhex\fR. \fIalgorithm\fR is the OTP algorithm to use. Possible values are \fBhotp\fR for the HOTP algorithm according to RFC 4226 and @@ -222,9 +226,9 @@ Configure a one-time password slot with a hexadecimal secret representation: $ \fBnitrocli otp set 0 test\-rfc6238 3132333435363738393031323334353637383930 \-\-algorithm totp \-\-digits 8\fR .P Configure a one-time password slot with an ASCII secret representation: - $ \fBnitrocli otp set 0 test\-rfc4226 12345678901234567890 \-\-ascii \-\-algorithm hotp\fR - $ \fBnitrocli otp set 1 test\-foobar foobar \-\-ascii \-\-algorithm hotp\fR - $ \fBnitrocli otp set 0 test\-rfc6238 12345678901234567890 \-\-ascii \-\-algorithm totp \-\-digits 8\fR + $ \fBnitrocli otp set 0 test\-rfc4226 12345678901234567890 \-\-format ascii \-\-algorithm hotp\fR + $ \fBnitrocli otp set 1 test\-foobar foobar \-\-format ascii \-\-algorithm hotp\fR + $ \fBnitrocli otp set 0 test\-rfc6238 12345678901234567890 \-\-format ascii \-\-algorithm totp \-\-digits 8\fR .P Generate a one-time password: $ \fBnitrocli otp get 0 \-\-algorithm hotp\fR diff --git a/nitrocli/doc/nitrocli.1.pdf b/nitrocli/doc/nitrocli.1.pdf index 677df212b4681ae5988dc5e2d810a6c5982cc475..3f785dad24c226c29fa20f36025b2205a683901d 100644 GIT binary patch literal 32165 zcmce81z26nk}d?7ph1HNw~f2IyGwA{xVuXT?(PJ4*C2r)K|^qNcXxQeIXU;t+&lB# zH}8G(ZT4QPySi&tSO48r)vFs4IUx}mdRit}lHUEu99U)oIs$8bGgvMzfRvGyiGwKt z%X5wbKm=&vU}Q%C5V6p6FcLB{ur@T};eoYxurt!Lgmp>F)0nec>p}LMQXNdqjtkI* zyb={%B$hak=nruf13vgb5Tek-*nrAaYu)%N-Kd^NvU96~5K**f-4O(*?d|AN2%Q}i%c)o9DlfGKuWkJ-MQjHlkMI2cJmI?g6Y_7%Lxd}NZh$fnSF#Eeqb_6 z)Dt*uO+DJ_^FcqIjy#h~-}AiX%WT;T?udM2u_oZPFfKTikebq3okLyHX2N>@L$(%1 z^ehRy6W-RC7WX>)tKCIsf?Ir4iOXt%dd7}@30aBkp}j}>+m#76;UcCcgve~iH?1hV zv3rM4p7!p}-k!V~l5kz$w;u`Od4mv7)3)#y1T+R0nBgD#I0oF4Bu~5Opu^fK=8Do? z)}gG9yiME#XD*s86DLHxsm>eZm!Y`m%=ckedix_MF_6z|(C<#ZX;?U*ge8J=(Qk1N z)xzJO*M=beJlRQu`Z(cfd1q#v4c#DhI&VtXBD!z#0WKc4MG=DNFlgpIYN#No*Kx=p zm(&A+7=v})lFHD}k%<*A^pQ9$e`4^>wSY*u)2^Vql94Ir(7m}-UdXsOIQvlTss7`) zzM4U9(M59J#fi$+enzH<-EgZsL#y-qVHd*<$Y2J!T;62*-~kk%?>Kl`@JzMIJqSB3 z%C*~<4rZ--?t&NTjKk-^e-ykRI_e1{MGO%7zViSU-H zrIhwmAOzy2ANq5m3xv4NRwNE&r1NyB>W@lDnmX9Pnw6zzTK6G69vx`O;lF%0X9bxH zyl=KF9>`u)u~0pKIAh0T4egpXZz0hXU;V^^@}5IQn3g)w9izLC|6OA=Xg$lIX13>v z+6}gaB5@Fw6z7}MvhT;X_3lAgw8rlZFdkyOr>)+BFrN1!ci*@xO;O28$2SW7>W}HT z{dDL1Iah~Q_2K8lMn``=u-L9}PUI8Z3{Y9Nqidy*jqcqQaU@?4A-^GzUIK53+Q(G= zT2lcbR^^za2PvJum^HeyO6mF*xp{)y+&P!3%UYVVvJIOyNjhfa!q|W|U_eY;s3SUC zTSPf&;yT&vNugPHx$p!0g`|+X1a*`3U9LDghjgVf-J> zyp((Vq7<4cTYc)TvQHqLCJUMqmW~L5UnF6ekFFo8+e#G;mrVjvoR{zF4UU2%E>5s% zaY)$+`iJOcQAlj!;iYjlrU=-VE-d z2BnVs2}G|}ZdKDs1KhKmAK26Eh;-;M{g<#XiM zsr&U4+hLKc!v=HrLw0=t@5Q_b_)LrwUu=kEO4a_^?g%SEM>U)|hO$`L=NB<5f_PdG z_Re1UFUYuM*LlJGZ=NZI{)O*mSsm3ei^(m@o(Z;o;z5gwwn>TGO2P>jBCA(Tc$528 z3(oy|zaHrZxQiYIu8FuP;0Ysgl4KQf3gl1r#y0 z3M}mq@H!z_d1q~Da(Vdxno`d=@Av|?1hTYB!!rSguV$gRt~fu~WiXaE{3fKEW&rVU z;ziB(FhzMK$XG*OcXbNic0$DpArX2tQyh2(q7Gb)+kCQgTFT%{=}tbVilJ*WH%%KQ zWw#A6nA^nb`?JDGkVW8;H&;$9E?m6bE6#TJy|^4&9=Uf3<w~UJK%C01jlzT+@73 z!twZC{e^_o?c{sD+mFerS+P&zTI`!Qq4b($wn^{fP@Q*KM2g2F`&q1tg|+Le0Lv*7 z$$Z7b-(ow3!pN@VX!$qx+}K*0R7pk>?K2l7cvSUL3%pY1z&CLl^TkA3*N*y!`DU`n zE2qzCs95_lpv?6{wAE1~%UvoMzmDBWTWx`k`;G}2b2z9Xw_!9$xU`g{d?5!}k5yXO zLf=~))glwOHtDZ zkiqo>5)u(5M-=pASsOQiZbTX4mIo>3-H)RN;TYS8)IAWVnZm3IWaoRCqjhr7@L#-9 zUlc$%oTQncPY%jJC^C{sqCc)ux~N0maxr-2hHP>w-*48cNnj4;-7W^__x0zaf6?W4 z4j$m!Xm+(|DWeX3w?ZON?-a`+Od_alGXDf3gRiV=ePyeD>ja!A~TRvPYu(6a11j7A-fgqMwYB6u8GC9 zQrBq?$1#Ia8f?a|z6TdSv6j>e?zH6bBdm+7)7;%pQK7>`%e|M(!MM$dh6T@>Kx%Yu zk-Jb7Lm`n`h+1r+>e=AKZ26{zz87Gx@E?2Jd zE(+jG5IwCO<@}cZ*|3Pc3)dUNX`V#21nwf7DY4i)-t}$CnFYh9ILgAgN;N6#J%qUk z$F1%gXIAxyzF9=H5Pj7NVT9^TWmPnKv?LMn`HGTpOafSaa47s0Rn`Js2X1a|t#~L~ zv)-Rgi(qWw#@dx;>l&^f5@BuX7ryl7COqU(Oli-Jw|AgdBPQ$)FyGEXFdsK>B&g=` z35CwelC~(cywkN8`~hXHw9?BiKl#32HRGu;tL}O%8-59aQ*Kq)DTNhb_mlme)|+LE z)p$Ac(l*a6nBwc!NY2H*633_e14!^eOHejVqdgSjTfrk5YkY6Kk6TkHg{22|k$WZ{ z3|?qCJMH194ILpeJ3s7C$w`8YXULtwfwcU&#!z5C>1E}F^7$c?u-{8G$TIT_^!wj8 z?kVu{ahvD&!J3As!IJ|~H$vh^yO`tbenL|WW5k)|9&HAx|EN9|P) zwu0l>5Svm&2x#u+yCvl*t9bAa9mD~M<&oTpz65BwI9o1FF@1JZcxx>HU_YEuMbr!( zYKy_)gtGsnFmgV-h`quvhWr_M{&F>vqbzkE>8!|UO{tWTIwYS9FJ6t()4g7OGdNHj0AarTCj)PMWZbQxX?4K5|C1;n>NvCqJoV zLDF3_c-;;AS`gBEmCwDyBtnR%yPAlm0OP5<(3LG)9op@Cd`9)AqNO@B@g}WNvBCE zx$+}2UHZU05L%_Gz+#qm_-i91Mj1F>>fy&=?3)t`<{MvPmSq|x34bIIfX@=kurx)l%4AJle9S%HkQ_=4 zW7kQPfx7Y?%p=-^L9^|aaAG4%{A^iu?ut+N;aGtz>v3{!T=cuAny2!5GVkju;)Vrr z2`gEiOu7fcs;AQW^+-tD!hRoR(WY+To>GDmBd~am^0h(4#@f zj>m{BOp)swB>2j90z&q~J z$u)yYgoZuCkWFFIA=VhHu}ec$OLLEkkMxO51{4jMEfsfc`Eh6SUM|2yCsJ5Sp_Jx4 z{E{E4l6RvOUjWSw+&n6&bC*BQo#&z_T>0TXHf}-6!ldLQbt|7!LR)Qy-RG7`4S_v| zhoB3uINvnlCHIpfX7X4bG&fn^S{W9T1C!BMh{atDdt^GeuSVU|^GbphLHkdIB~=e> zr>27F(IxsNjwZe_F2;jU9!cDrM%#*q#(-kpn9I?8cD?<9QO4R7=0}9s=A@QJ0`T6aY2xYHVz`@%n4dAMV|60 z@~wS|!qFVS1rpYq2}4W>y<1LJXkc!)PW{oDPm~%?DCI>QT~{j@X5YXDL!q3HiCB{Sn##(irSYK#WyPN z4XoiA(qn6P)rg&8{fvdit9Aq}(j+u-p*o4X_8sTPj@gAcxWcVy*6S={oh-S|i%L}>*l*JIi zSex!mj2s(3|CtnKP%>ZV;d|n4?t6s_!r;0Ruj}i}dmNC~@==aH3cH7&Q`;QS`C5T+}YH1d(5_EOrLcjpbo zYx$9FKOIn)D6*FAwwtjc!x`UKb{)IZj)(|!6(F+ZP;+CZQP$2peCrbzYu$i2q0)8p z?;l&)sx{g#NNJJy$D zT(B?26R>KYdSah2*u}Ka%mgzu&=(eRZg?LzXnwE(piQTdAAIIjvJEd4@8po(s5wd! z&?`7Dgb;*QjCz9d6a{|?0LZ7;b6}Ici%MYSmPH6N%<9(q`oY0aN1FcXPa4%?XCo-h zcR<9U6=IJ!8$GlmFM5Ol1B*p75>ek(M(Rq}R}(m38~|E}6_Z zzB!MbK8!iU03CHqfLHuo49^%OSs&BVPgau%Tqq#}8uf#W{~&mSn@l_Jr^b#4hvI_y$xKy}h%xI7O{P8swqxw*4D%&ksP(8?@rM+1KOphhy*vel_KBDD z7_tDlVpB#RQ&>=$G8Ci&^X=-2O1h@I^L*MyyR1bh(3Kv%v3tp>GISsK+Y1Fdedv@6 zT?rIxsl^_Zth44_H;Tqce|c(bl*w;O=dwU59@91ZkT8CcZ@t93h(;-{_n6Hjkm7#J zMfO$Nnt<>#iSzqrDJgjS5@Ir#F3IJ$1ss_a2@Lz9!4~;y{R%wF)Mx?P=>GaJzkK8O zoAhBysc-SwhA|Dtlmx7C@z+UUcmH?@8-6f>--0#n{)S%s(i~@AAsOXQb?E z+}O#*R}%5)I6P6_Kw66momc&4y9#D5r#)_`@FO(GyV=|C@=(IV9 zrGYc|4aY26Bj&FZy>_w#azMso_|=a2ko#xRyMZj24#@EjP&U@k#a;yFcbKf?3bro0 z0QrgzzbFu)vyI^Wt9G^w;Xvf+azO08IP!M0*H1yo!ZbzOapAWJA+Y$3W}@ZN z(jyAcLD&~8b7t*O=s{e5P`Ivq2esGiW1DYv9ZR;x+#;!38!hjR$-c$jGXk#;4R7w6 zzK`Jru!eDZawD>AH?r|jCk2LPP^@r zpIL*RuSl=bun8OB2&x|LH3PFD?4@x)kH6G0f%2+6Gp)bB_A(?}j%#K60>(L)U9>1Z zqpNTgEOj4{Ef#3M<}B-Cc^HNZp)Gfa@g$9VaoK_kQBNC|n-Hic2)Ayv%S&*VgW12O zPPU0GN)q{nMP`(1HP9r#o{ysd9*e^ySTD1R;mx}AW_B$5nRyz8Dc97~HSUZp@GH;) zFJ*5uvG;TpEyBG03!gue%RFm~x~!q#b$dSsz6c9}Mk|6Fx>_`eKSc{ZoF{`B|7X8X zo7^|R_VUu=Op00(yYL!>TcE1Rmt6&+Ew)*RzBFVoR4(H0y#xAw#?B6=l7Yx06K-(Q z0kr7RYU7sT*q^$2Sx??E1|S!B^gwUZ-~AB6`rgVr=9*?wCiRQRbfgBR=8VDH&()9s zFWIQ=Bt^mmrkXRhLX5keXxzs8(sXlXA^8&B#WJ!t-@j5ES_qjdMl;gKq6y)n|J6;` z&t+!QeffN$IuGMC=*to=<8oVnQVK=k&tfVF!!(d(DY%}wX$dkSE3B{&Z>c!tWVBf8 zmvD%bc7L#*Y1Zk0hh6HGByH7W!f|CY5#+7k8^a@RSDil9R}S%k$5n@@CilYZuGm1% z;EC+<1%m*woXY`rA7QNIe?cir@Ou1`co6U4v)U{@_e+^M3I|1n)bu)#48=^7EK4o- zvvLY&1wStKqdX65VGT;es{Pu(UIOC6VLOfxSG+#@J`NWp>qnVuXm^`cl%stG2rDYG z`+nrlb}po}J~AEERD&saN2Uli0gy~CVLEuFO_vPJ%`MdNWgm)>){x`^{VX(Ed)YjN z4KKrGgEfHEJnPR^?WqXNI)VlPcjMd;`*&%uy9n1-4D3iah&^d7(q9m!1J zpr1lU1kX!6O>A+d-{DgDQ6L3iC5M<)W%CR9wF-Jv2ogaaz>UgFy*KX=t1G*AZw?oGzs{A z*(4(L3+bJIWEwSh=9W3%pMW7wXc{AeoQb(J2e0WB4x<<;wQ#A@bF&FxwByp(H?jlG zy#63WazXJ%qHcS34{zvTK9Dre`qZVE=GSLTY2S`aCL52cFqt0L{ILs4+lIX5hTG*~ znygU~UJd~&tsRC#AfjPteBa@B%8e=|2!8o|ix^?qyphHRb?8Ea?2Ax4f-gl;BSzoU zb9EJp@4F)mXYtoG4rk}aFe5wOzWrDz(iF9l6EPWgV0ETDLdlvhofJDU~Rvw%b9BP%-BXC3C9&(lU;qhYD%4ZiQahbX4_c1%- zHk5QGHj65krP<=VJlQ$PZk^UM6Um+eo*u!v8)j$zDf)d4YhS}(RwkC;;V%QjKZU;x zjQ>{nt3GEpCxYU+r8?N90x{1(mIPajzBR!xj|;b_9@@?b8&GDW?Qr3R5vPpA5D z%B=UX{<~is9<{ZxRitjPp?JPaO4WuH`qwtKwsgP~XKaiKWiIo;h1BN&$$G9~Km3nh zn;T)jPozDJ#pMq-)T-oC$ku6M|EeBX7OtDy*l5;U+S&juK^HI--Zmxl7KPQ1`RXl;+#6KtqF{rcl-FJ|%kfzT{7#ug*7TXhTG{q=R z>h{w|=3`6_Z8dOH5_Z7|8hv8N)G-!>>(J4~^NTgRKMxVh7MxiVQ%r!l{vPghZ_Q_m zMbw0WOKmqJoRbzM39=7lF6cy?6u6#Pal)D-(dpEv>T+fE5Oesp=mNW!Kdf|c&WI86 z;C30ZYSfdDmc5xV2oVD#{NIKho#nHuTxgMeYv%lLkuT^hf{z)=hvc`JZcATAnVWB+ z?&u!?PpIb5N+yu6)t@^6QpOgDKe{a@hUmSWq{`Mf&~=C{9t3ea@X0p}XD^4@K6t2|$2=Zp?T~IKoi24xS>OOM380(UgXu_#4AM808b4jL4^0tAh zR{;8RXxVh9+x`Z7h~=MNR!EL%tNKqnr`4%i4Fj;t7K=Ncx|d#bj@0D#}?d;-!dV zD-^V>FKvJ;cgMqa)v6|Yta9!ax?i;a5ZMW&Sh5<~PI)_jJ0l@Y>6-Kw%@yk_WlDlx zNl+c3IDFUgsxdaF5NCq!=osWh(qKm;cve(`$>9FwK`ZB?nOzkHMYhR23QQb{5uDQ3 zKvoy~ljdZR4fRv(pQ=ZeT6`=y)zS2E6z3X9y)q#~+?vjNx!OSiZ)0$iTI3gkna)~+ zOAdYXA-Y?KWGzXS=Lqgv%Q%ngbxfrB>*A$axf}-~(A?L`1R#mZ@<0z~!4lrU zPB9%5=p4zxxpdCh-FrFnu@qRDotxnzTJe@}4h3I6=l#8P)7dQR-(4cC-1dl`^es7wPD#IL}iGJ9j4XeA7Pm0x}bw>_{pHL=DW?s=peoMf9#Q?Qv zc*Y{S)2XGov{nmt>-1K#k1S0+RXM!06OL0e`G)nwEe!bV)i@_3B@;U>Q#2{91dewp zRc>Hd4(E!sU#bS01$$n;s;F57FgFJz0?V$qv;|uHnh1ZTxY)eLtl`QKyBSZto@z)j zGsFkbs&! zz+>JM2t0?HPGF*>%o{8dQ%CctOve4x8e_`3o_Q{&F;Nq=Tp(BJTUG4LOpNnp0B4vJ z68O8@i&jsinfLLkmA%H@vdP~2huQn<^J~uSneeM{$&C;nOB}b?cLQTP=A$nh_`>8* zi9Ao`KHIMc7QaUVD)Zu@q?Rq?!i7mr<;TuloB{3VH!oV}ftR_^-yG0f9jCGleinJ% zy|KgiE)|LPHukZ0FH6tmYoXc*DL;Km2wm9pDjPF-KJ(t|{#J3_-K{o1%+ z3nAzaZbzC#+Noe=qUm67VsddUE3-BIo6@6ARCazI=^t=PcuUo>S``yKkhRNxI$~Qf zoo~Hg2nV!&S$VH&>dx+{I@$)1Cs+uI_tYMO&>naAL}+3uyd%{wAEuY)k&qC3XC`Ow zgw}Yd3mU2)7gexJ#{97IO?k4*OXKk;3va>U0vCINbg{i?%dyZ`|3qHTtA|uoz>@Tk zNbKoNHdAQ*G}e`#F|EM(hMOBIF0K6e#?Wv*amvKbVw=G#h%@_PTND1JBo-q{oRS0(Z6znJ zP{}Ck?86AAwmhry+XCl(^dRZ>kf@UiJ1MqatIZhGq{6J?@=>Zawnr#0Lu!;8Wtm(q z$+-4OHD1%cupS+aCYk0Gcbsaq;`0Fl^Bz{*DM@*yP@WAjTur1?DQF&DP&5{a#+EFK1LBQ0djQ>j3oy`ZqXc~bkA4m#@GduP> zR;ih+TR`7clEpI;;}{97*)>XfCe=h%>1_f!Yay&j|@Xdh(fA`Ik;DJ!8;_D|>tTzg`Q45d;VF5z?IR+VKeY-xb+#|GI`?PW) zdum9ebKnZ3TKtztmCh#C!xhP25mxFfEzBu9`#)2=-cZq6G_Emx?3if>%8ht!rdW6XOlfl%N-|9l7XO@knsw!G+0NHq z7scyW;W@DCb1NI@MnrCLRKj5#PHtv=-hIOqWZlO+9zXCDm|8s(_ZCmoi~`(T3voe6 z^d~F-1N8y}XtL+9z1 zFYuXI9R$;}l@#@?c&!fkFkm)bUxUhRJSN^wb33%bfnL@WImd65UyzW8<><$+mr!J& zIrox+%Oc+Wn6F=XZ=z>X`F_+YBf^0gV;r)$>Ueu9DROW+X|cm{&&*=e89rY zYYCy0zE0bp%w^Aog7`$JB`6@-3*^A-+ALCozn;dst zd}UwA9psm7(mL&C3fgBBPSX;8vzG)Fe^YYGu^tedtFrwB;0P>X3|*I8I;xW4x`u7T zoR;OhaEbYv8f(^jXZtbmunGC}DJQc`!1^}(j&RRc&Yqq_cE$(t$K9rC2F&|5%+j*l^pChj$<@XPAg5rF@Z568XEZUr0O>bs{^Iv1J3&1M zJqv4--+ccBuC$SZp5ZfvfbkDr|6uSpBlL>8zYq)ykd>1rpy%QF{iMGQAO%*~*M|Lr z%`3wH#D)Sr11$Z^GJyg>fu0VQ{#7pk1vc1M>-M)gFWUQE=bt#fLh?8D-{km;nBR5& znd9F!8~?j9zV`5c$?>(ze^dY4rv7c!L_p8p=w(&_h^mMSDyUE?0WFQ}X~dtq4QTK> zT?iT38`uGD9IWjK=>J$+dF`2(I?wY7(9YgL&{WTkfRO*SYOe{) z!2F`{fBj)(d|^lj`>&~g<^F%5Gt<3rV`5?=c)5GIKF_bucQ0QC))yrFabz`xRpj`|KS^ZJXfo>BYP z0C{2gXBYjYd3gyDVG*G}H7{UoVfasaf0^nO{+NgVTfMU~{@Z$g?U&a!{@LE&?f#e7 z7qS2RJom#H7L^z~BmC71nK&o3pODX=dk{;0#u%<@Y8gWoIt zmEWIec&YvTj900iOTPBmpVyZXzw=-E<2C(Ed%0(Op*`O}(_vq)zw5m8-#=)t^89Y` ziv$d>Bm0kM{vpwS{(a&0n)m;JLuOXGzoCVI@pWPa{1+g3rTz($KW4$-D0_j-Ul9Ax zkP`wL8yh|Q2hR?HCM-P@9l#g}OaF`rOQ4mbz4kva_}d$Kwwr%JP*O=mL`3;d2r5`x z>RJ6~48Gcy|0x7t6#nvg>4@Lom-Gt=U()|~VEjE`e|O3saC`yWD;%GJ_R?j)f%U@w zrQ{0$*`C4hXZ|ZlUdun%dnx}4;a4EO!1g!D|ET>Zk7oeodz7oN|x|J2#PnjT+DzI^__K$GR~6Bz;Ht7r3H zLi2A%>wgMOMs|R$qxJK78lZ`(11vowE8y9t>)D(BcbI*(Jbxb&FVo;ZEYmAkW%MkK z{!1$+@a$G=(y%fU&@j+FV}p)~fQ5}w`{h87iT$(ff(7u~8@#yI&$-WDv7U{X(Tj9{ zBwwEMLVKwS3;4q{@>`i$JbUD@07VBQOBDioI%ZgaG|=Au*%rK7z86Tt0@VIw!^HIb zgcmdU?4pwc^Z*6`Lx2&$1YimD&~(7f1O`SS20&o zR7Gz?Mk${(lf)+J-ux9&H|bnbS6_Z2Uq|_c99C=s9lVnf6ddK$i`UBTl<4`+4h$9) zt?~^I5~#4*-WM}v@Hs3I%d(P^n*6m|?x~FOSD5au^PefbaP$mA_v>t8*qkbCjltEmIk$|y| zMmDI2u8>`rt3*v*E=GxDBHoYc6!-ZGjqKj(;i%yeWB&;*Qg0frn6a z@1vKmSXw1gSH0d`m7xV$f?u9KP>tgful~Jeq-DoqFNEhLO@j|5Hs={RA`S` zWiK_{-b!waxQ@s{Bx#QOwD>;DFzN6LCfaZ}&9!Q55GkT8o_{%z3Al}_z+^&z?i4xO zp7MiR#H91b*YR+Tbd+Vt*oN6Hgh>Zv3|;ipxlNd+)Lk7e6*syqS7hp;yjE7eOia%DScNRbw9zD*JxchhftyNglzdD`F`PTG;EXtL|nhynvAV>Qy z>e+LrXy=MNq7SR42> zhWD{`o`r#^(JjyY&HT5g7!SQBKB|p$=&eIFO{S|aLPV_6Y6&pMtvTgq4Rd(s-uyW2 zKj)m@EJrW%-*%%?yWO(Ncb%JmH5QHa{{=#VZ+eCt9kfcBpjs|(IqF?FX*_F7GCze> zqq<^Vj5wcth!n&WK56XJ#cqSF1(O(Va$Y7ouXrxQFna0VwPpj_;XIR;+cC@^N^G%h zf>I4}<&UdtaB@0Wc2|FZeDuae+(=MSlq_wON22!Q`yF0M2KEzB;dY6te3WhpJ7nEV z@f#6cn|`jr%r=HPMdWrT>&^TeIb&-|TQ2S>#E=uj?wqjn)r_M!Kj3j?IsT(v0L0x6 z^Vj&aV}l@6I{fzjO@>tQmQm`y8(nj^=F(PekKZ)PC zX<;kWXYgQqIf!SS94_W4QGzb%UQV)u*fa)19pkzCp%S{0w?<|N>=aHf(l?rUkg5tD z8DMi-)@XDw)&I~?)`Z|YCbh*tsGhP@7}e6A5#6)3(*0Jyup@keZ6NIr*N8*AN_fw@ zBc-yHqA2CzDAj=LgB{wtNe_Zbr`G=#qG>yxZAPO8y6@MU(zN=ze*!I4atLh#>us-b?JfI6t;w0Mvo4S} z3I-6DT#C`%unsKg2RoJLN7>tf(pA1NNnYlpSMSon$WA0ALP8uM!Is|-DSs@+DBtlf zfl&?b+9_peT8)t+E}ApoQo-p5_xLUfCr_l&ys}n0z$$|iIKoYkdo&%E1;5oFf@s>c z0OgM;3Smm}^~YW%bG*ODu@gs1wJpssx3b2^Eb@qv*Z^5X{JWKPk{tK-^XQDeS_@J2 zcMq~5!Xw)eW?3d@2#p>Q8b87OBq-|~4+tp11+thZCaPoRLr}^@C`YlF;Z=w4}GauvD5I{U~W$?s|8nK^CWW4cPPRM3eT{8uno7$+~8Uj zU{2U3rZ`t%(K^a-Qq#dzbZfU##?H}OJ}HSV&zA4y1S6F^;EgYZ`9*rK=2?tH??YZk z_${V-AKV+e1els1S?xo**tg1?SE-jmcIH+kCr8j)%i+T-ew%Cyiy&q~B*|ho{o!X% z5h)Th+shL!M#T8dWP2;s;Qe7&+2DQuwgqOla|is@raGc&v- zbw;ChGnZrzjOzEa23K(c2s6$inE^hk)v#7OZ-kCf_*xuG(X&ZslaEbKr+rHm$juI^ zuu4K%h<%6`2p99%NLgsdkQED)1YoZ42BzQef2MTbpwTRN^T3hmv=Tx$;KF_KF1dgA zAi%hH>`C5&4dLxez1Vy}WCYpayy=u~Z8LcnfuzTphH<-t(Aax~*5Kh|{Dt)=EYs71 zJ!fw_=HAUcDk$ZrP*+@?CA{|_E`=YJX=65mzYAHl$vq}8{R$y3f#HGvR=ai~UDb9b z+PiWe8t80d_aq#;J>@EngQAw!Q~ax^6Pr*`bNqb?`XOwv=q2i0%|?6{j;Y6NmYWq( z%_EZc)2=9Q$8@mlq0X$kzE>#07pHc7rscOoG>$T4l`Y^C^&0Lp9ZgTym!qm{pbWZJ zM8kHC?OF8aQClD~En|n(Q&C<6BM{noQjO#5`^r>TULH5P${qOc##t|M^oW!0P}3xP z&mtfOt~P;;Mi2qSlEf4sjdCc5cbA=ss-KtctVXn_Tnrlnke3#6CwMNjb)?IlYB~r; zFUi?p5mpxR%GiVVP)E~*->}8YRJqg_*$@68?XlOy8Hy0Wl{@iGiTk>OCYU_vdKUloOdT(c%MT9GDGvw=4YKJ&n$)%&DKK>_M0-h^Y8h2?JKLAVYFmjcRPz z-Fxvs^?E4F&x%%z82%DmQ#vz?QxiP4`~-O;#}ZT|IXPLiWqD2P^D3hX5<=yW>?$N92qHC#>qRV2H0Tkct`@ z{RT(g_C>%u1+=$!idh~idd&D&9dFS$rUBy>Wm)JzG-=R7CrS&Mw)dUHn-+78`>Wl| z77qC)_(h=R5hBMBzuuQuPj>c8#1?B+wvd~T+?gs2xIDNbeQ%*eKqt1G4*RH0jp-}! zE4esUBT+PirvS^K&^YXyrT%vj%{DfC?vW@0bxUQlUnlazSl7l~y}14uhn{wAV9Sml z{S`hupS~L%2&kGap4{*GAVrf632Ak%!|7iAcDZf>Qsl#Vf&>v3#W{QKn{BN8?-%_E zZLy-(h%j6qFPS!PAdkMqNm5V4cycLq%3JGoDGW2YerRpO-kh>cDG1{o)8cfb{PX|? zBCe|Knb7*P=9vp z^#S^Nb^v`lJp*$i2MZ%(hd*8Y*JuJ@{2Y=$|2Y`}jGq_o|D*qJ1~7k(0bZl^=SaW` zXl3*q4p=|`+5l{xgC%Q2fbAc#fsxa5#9$9}`726rFtsy!juxD)pW_9m=ZL`t;0kav zva|jVfy3((=-&c|zpVlO`+);93nRMwwvx z7M47YTr%OHL1&aMv>>K{3baAe8zC_eBawGFq4tr26N*8zC#DxFmhKvw?jsF5t7-14 zS=EwFbRW(k{KJCgeQd@3@yASQz<{2bkc`= ztH!D0HH2Y=?sK)-*uy+;J+34ui|?PKKXi)V;5WG$e(QU}c61pph&W<@-ofbIH2}b`WZS9`Q=U|<|^;^br(VRz_oh$@XX@i`+>o3-9~KekX5P!`$yoKlR z$F-iW!!9B}`m{~jk}2}Jb)~Hrd8-{D>>F&`B1uBesjp%+JFqB-q1*1bhMp4+Wk3$B zn7n>cyL8vdSE$+2)fH1hC^%)X@+(fONM^Cg#_?yYpZpwGD0Vt4T2N$o>itVA`^ z@O|D96W{_)S2;_y#M<)ve+~(No*6FX<#BrIa|;mXC?ZxB`0Wf){$RSUxrYC8HD!DY zREIFsO#b;M9Lup168_ z@oQN?fgfDh-KB|5AVrN=Pue(Aw|3crf8w%p%+=AU*rSgJP+NM*ai?7%z*voVe+d}L zC?m7^pYYQzzanF80o?TN_*-k*8k!|`|k$o&-Dyuf2 zi{*YAVnp{;rND%GfT-bVw1=8%m~MmHP>&NV!=|RVt-iEOPD(~O;{bn@k`3y8z{8j> z%U0C~1zS0+SoCPz(E6-{1A0$-3a3pBnRZbRlp#dN;cZ@Lh#~m#QIjm>B&?R$-HOPR%`Oii7}9y!24|r3t?{ny(rok|rAJOr z(*oypn$T$k>|-!Qp8qEXj>L3`nvQfgg}YA?#to3hk0nVaA`13K%@68{Ox>F; zGvmMlRcobgP~x7o%{Ji}rkhxG0=7BhLmt9z1(9~`)Fztr@qx}|Pn+Zc=xDOQ4^E=v zG?<978i$M9R$*L1IZ2@@uBND8NyX@|B%9`%XS;6hWS(}W2T zvuQZ*vDZ+muZ|_YTPZ7_ixCEaf^r~hMX1+=_EEhmh#{KtQo}9@TR{)`g)Wf}eCfVtx{~oWAO%)9vW_ zYOa*9rEN?Ye?w8hm>V-c3%S$>M9c5$G|pP0efV~UsMr}HzPoN@8$YK`)pR3mXK!ov zzCBm@=k*7%Hq=hI>o9*{uv9$K9myz%2oXJ2)IANcp-xoU%x1XP}i`#k3_?>ER} z-bO@REiBvb?h%Vqe>D3tup1I0Ax}v8gK+~-nlsbuUDeWj<0C%)fSYkzoD~PQx#05# zli0G7Dnjle89U-8Ddmk`j*BTu%{y%ki1bR(TiuLGUW{h;`}DL&b1P+$HnKbPHMH19 zS9d;3*?{jycE3=;Bd7!B3A8VJlJVk8x1Oer_}QWyW|W|Bu*l7)Xed4>-QO8)T!pHW zxx`%3-_KGtibg@J-hfykltzsm9zon#Ep+u=c}ip9k5i$+8K1qsa6|dM$*8wA zhmE1Sz)<`61Cw?<`DglcUR7;iXV%x!1KmQw% zxehT5s<#HqJ+jxI1i9bZ-vE`FGIwfU3CpV#%L&=YlGGx|^N=Q&fzMKTRXBCW=p3oLKxv1(}m3)8g;J!mTWu#m; zES2EAFnzJW<|kC`g7BW4nAKk?)BVJXX39CC;@UYv8gcnQB5DD{cmbAhyaz-UHPgO` zp~0l8S1oo0wRy>(_?(s<+0SM+#z1j*&&1$YF?hS?2()i#(DC3oafo9D*cW>{csvqI zc8ZuAh%VjE(D(iFM(64wzB6ay5-oW_g)U>XNO1}>U&BS9x(%!L{I58$tq@N$pgh%LKM3fBQPe7F>RzbDVeD1h~|V*a1jzB(?d zZu?tNKtPa2KLH}(dW7MK0e<2{@&l` zz2}eloU>-Fz4uvbuk*)>@6HMo5+;9P5Kg1fY(FL)PX`Ys|B8G)IKjE@bo6z$9dJ<7|vddRG3IGaEc4b-KJ@EAD{ zrxw$_tjX>Aa;+TgAd^t}K!wp0g451ZGkd*|H@Z1-BJ6q7BUz8KhU%Scw5%3`jck{? zI+t*b920YfDq)RExWkJXPE_4757{)u=kU%9et z-eniCWJLzP z^AEyPg!Hh)75~g*k=DH^eZSI1Hoe;E>4FH=Y2ASCNVD+q3rCiQqBsu2BMynGp?oQo z%1d`f{$%p6o1C`I>2JM-G8ph;K1)gNytiBPils&=G&@v9x@#?d)tGKK{W@>V%(?sl zFl2tYBv7DDFW$YR90wnQcD@M+MB{l{_+7k-E}JG-ckH88A9ZYQME`C6rHrxq$}5{- z+PAP{Lw26$@^^OlA-799M?Km~I*9oklpNy@slsLosxEx^Wfp7t*kf{3Tl=jD-=nVB zUvWIFT_n^Ho1J;g<9AN+J?Z+PAOGf&=A?RF_=3Tt>@^ZbyYHTck7n=Az5C~aqv!@u z|L6@2=o|Vv+fSMY!1p9eWr>By?bj8oH{y)5w>8e>9Kg62+gujiWy5w3Q&WVIGLF_r zQf3)MxK_y!?e$7sT70Yd;)CEQssPx7A@?2Y28MH#!ZT_4qdt?M4}NL72b6~z`z;pa zl4lbTH__ZG@cw~b96i%UANT>z2c`+XoBS<=prf0#wo|=vwWGZ;otVYep&gr7UQLL+CUG8 zUPXfZ(zhk%g;yaPpQc!<=*%fdDqVVZO1?|HEU1vv%je9{AtAsG`Kn+Lx@C&Mz*VnH zj77=;ooKPO4K&d|yE!mdABgtoQfr~`tHES@o0Jshz|SI}T8KRq^Mp9;L?_j!W+bc) zQu;Am9b;#i8S)I{Yzk+;sxhbjOyZTMa-9nJiZHb+IX9;6DD1`YAi3&QPaIpaSyn^1 zxzlYecjk;x{Zw}Vq0-Ai6#U12IMekJE4o+IgMnvs@goVMQ^o?sbhpkAv;<4LjEO$< zV_w;GfRyl#Bn*97+Y&Uj3%!9}vRQ#%y_{nAAF^4%fZB(mc zc2)LuKxoqjo$jcDk|B+jMs|J=SKM&InDkD;On7+HMf!eAA(Il%^6k~!TZn_2$Bpqs zvNCN9`SZvsfPIKb{@fI_!L;5Rpp_=^#Rfe<8>)__kLW3<4s|y17dy?xp@>d2R8BAb z(n$qW#fzrIac7(-!lH-^a??S-{=OH`ZZ8`-9UIB)5NdwAb&LMN+vQ7xy!1-$d{tFS zN{Q2*;23ckOw=jKwCq(d>Tu6@lG3j+zU=l_9(jj!r*z54d>9YDjd1NO+eQ}!DthKX z9qw}*n0!~uGGnX)Ir4)Z4rJj^+F)I`VaP_^bYr0$mwwoq71H(Xj}Ns|5DR?4`#ikO zNcY^)CFeD4NImy)lOHBJS3$_|OpmF_*I@hLV>6Ak1h?(aE<&MS>CjXRj^};{p?jsf9U8gY0Ik-=XkO3_*kIlU7p~=TNg%^$WqBNCWS4BPoyv z$j`kFuB5}mgNQ6TAG@FFm)WuUWp~>yoe_}M`r%Z$N`AEQ*ZiDe)yXbb6@`~f?15&- znsfaG6p`wQ)Lq89hzN_>I5&vGOL+OBTVse|jdE=%@oh&ww$t=XFJ^&a&{p7U6!yrl z9U>ha^P)n)m}*qao83Gmm&eTL!=HqANa#lPn830(OEkWC^8u0vMVKKs+tr2U!TJj| zoxE@D2eI*y>!^4s0$+W@EVi^y*^8w1JFOW

u7fX4;`tSuT`dtBY;E;82EJW16LJ|`TBLOZljyH9=}e?*Z(m`$FS{I6F+ri_ z8Cmqb>cB$!=Zgg!*7h=?`{^j##(dm(-DR>SmIoCLw;?I!b+c;5IeU^_UC0M;98hRB06)68z&9&t1YgshkGKpmER{=f zc(t&$8&Ny8OGEnRIkiKcH~QqTX2#_-jS`b(in7=)a4=>FBCU6Q%^bN+7(jUMLwcAS z@$}2cGw=v6nO)if3(`C?vp;k!5CSef$PT=U>8b%!HLUTc43Si&MEVtF#- z%(g?w7=Xp!3~$Hb>v(ONTfmrS087{10*4+9D2wPI$^ydEJgOqX$-XohuAa7zT^%08 zkhpL(8{!vV1nStMhTN_pzb;}Q_jpfBVwL%NI9jaw;RLvh_%0>&wS_Gny-a)`*uUSvVXfxmiZqebXqFJ{-tP z4%^DvQct(t9C>Dh0D;!##Oehf-NX0`YZq1$S8u{cVcKX6NmREkr&m3PqffDQ@2HCI zCxE)~R9|JEnDf5t2_C&zgDGV5sTU8eZ+x%d%+p~rbf(gwuIr5@EoZp4ir~dNup(Pd z!FY-faN>-gnoj-p;>(TJBZ8}M>m_TX&H^JfAs7JT#K*K#US{nFP{~cz2kw3(h6aWM zU&C+u&0Hur!UzsMw$o$*ltMvK@mbSMoG3_6sG(l;=EW8TpYj=A3Kwj|8I6N0^@>Nf zGpjdiz)RB<#MrepM1{}QA(ci=MDnWUZ>Z=bcB9zu^sAUC=V*g4m5X9fD2ti}blS=% z9xkC@Mi!i-oMRhBz(%3f!lno*jV}xk>mnHZt*?lqbb5uDWg|ZN;=RTx5t1-nb^Q=7 zvu6K^a;0~wC=6s~qC2ldYr;gTfZ?U;uq_c0V!`C#@bGQdA^N*ZoAFpKjNfDYe<`E= zSt0bFDs}!t$=RQUIskZ#AIwR{34&J-f;sd` z4SQj}b)St?Lud?fW-KZltF%N4k2GExq~Kzjq^x6NM+#s|s9}={Alz@3iC-7AP3u=4 z(=wZp+BE;>X5qQ(IguTFmQwq=?rhe5;EJ2H{|TSKX+KfQ$#v@b1q(iu{jEW%#t09E zp-`mSm$tTN;gvUc_l05tVlUOG0dJr=oFOY(f$8~Xf?BzJqV>$iviKu{Dp-75mLxTG7I|=l+ zVZq@jZ)N##v2Z>_R@fTO2UwFs>4!RS?)C?6jVkWu&mRiz%#jeU*Mhv%oA+9ICEcUW zvUcQUxtSk3N%Fr^aQLp!xj0A(En2k3+Ivr;m@)*M&!2cR;ZkG}CjmNbTMHe2xxk+8(Site-^i%(*aw+fHfGA>iO zMY>_PV3>IueeNpi_X_aj@1jxeD$cEr_IFCVqS;TG1z&{I(<@uc&atY3V-nWbt!ytZ zHv>?d`gz_Rc_9 z+~)0zXw?U_o6(lWjxJrzZ-*~hj_&4ORWCz2TEbo_@EbAWstBd(ttCs1$HxWWq{R^g z@e6RR*;^C6l?#)8l6ICwcx#b@d8tWv2UgCI)KAo>cK@7ys&{2| z;0jE9rR9W@_y_dn0pPOf0RuZh>Xz!pON)nlL{RnKfJM_`^;AU!F7rvTWIk0Z3&i7u z>5Ur%T%lb47}N9BVMCW;nTypPnM4p+CdUiq>z5miij79STV<*ABYd&WuWdY7CW8d9 zP@gLNw>J+Zq+wy5te*BTp7h!7g32-?Z~rX*vh);`r8L)wc;k!nu&VxhPeL=T7Bjn#N~#>8zH$=GKSG*9nZbjb4M8C z9ZqCR;&;o4hbx>))lch!l&a0?Wujx~dwky`GiC)a)$k}h4$+!^trai|bIe_#c0=wL zCef+z8}^8fspLX_;MgWqIA%h`77p7GZOQ_iOrM>Mt$%j`wW~=Y#W%pCie5Xw*N1Dy zO}JMoN(qVNvJW%`3JBJ(Vy^H>5c>^;j|Ic$kcHLmgWrk?Mg-vtc$?qZ9c<@cAHREE zd)j7skB4AEk8pJL70spiyPFZzHlt1`9QR)}{$ty%d$F$G)LoNJQltrOc zPQ<)k{=+*FQlE3pH`-@czyt)Rp3Wf3CGg!_vwb(8M?TpPxvhA%aJFCQB5&Xff5i6< zC7+1bR8!lf>wOAsd9{WkC*UbFgu-*Mv-&0!KST5L_^sWA(9P!k`_0R>Ic7Wk>7oj1 zQm%=(NRIq{*Fs$tr`&@e42kZpXtS(Laj6VJ@EaDnauK$y`G=oj9ING5-}G$4W(QK6 z1ayql-JyyE+n?1f*9gv0Xv2=ZY00qaa?+Q(&W?$gHnPcm7;>>3-&V9H6!|V0E7d4c zI4X^pQ_E0Q%DTF$2?&da1lK4jRmB!j+Aq4FE~}Bd>YH?r?pBbe&nM7Nz3pmqPy#K` z71g506o^yqTvsbVY0frTrN-3F!hH#L?m5rz$ zfU<_GbNnS|M-E@bE>VE)*A&rFD)<~nPiyBoyoYvsoZeZ|qnO$rMAA>0zHcRDaXoB} zJaNm94Me*Qrrys6llGWst9~KTVj5Me%T%#X4J@?*sx${?5^dC{bmhO ztnFe4W#28PcR(OtT0;0$3dVkCQ^zBjEh1vJ81xg)m@s*3oqBgj?ul*CJuLR+?zYM_ z--(%7fJ-jDoor}mMkL7^DQ^M31S^_;Nr%TGKgTCPvd704z2jC{Lmeuki|5ZfVJK9K z>G}oy=pPo(Qmcn-k#!!L1?WO$OHEK5gEoj*i36u{BDyP%dsWDg2`?RleJ;$Q_tsMQ z@uR5eHv9su2*Mv(@48|k(E9G*`!F>>BG)1y<=kgp6D>aA)At=}s)e@AoNZ0M+~!I; zY+R~Uyj088Cer%O7&Qw$Qm0U>IGbO1T{0&-jlrzOB1ropp*`9^qyV=O4Uc^mvvKcR zF8g~u$2I2L$)gdc^Wx4LtO0>T~kx_vifJf?qUGPemj-SR5`^@gdZ1+ z%?sbuq`ZuLpid-8kC_uGVSGqGH2hQ`HN;{Yr!i;46NSy6O?6v7!^7eTmU@*uXM&D? zed~3Fu99+TX%cj(LvQo?7N=Xbt}LNn6K%5~DmssJQmx2c!_Y0eW1E{HvtE^O)w`=x zEw>le%uf~5yC#Jn<?^H^?tS0-boR#P|&J zq^%;JFuxvAc%q&&%5Xe&E}pKwY4?59P2t{S>NPnIWWEK+JUsxs2_sIOm$65dr_7$l zZ9^qPFf@r|^g@?f;c7A-BDcps@6{JRx&-KSL zlFp!pR}7cO7cnlV7D)CYUR}GaErrRRhlDzpY|QLygG^x(6sm9UCl}B?#}u$ZeVk9! zR!RR{FqYCsuXJvJdMZ*)TU%8#Ij3vl>BB7wS#rQ2I@1`h8Id9HMG#%Zl7gF>f`n8e z6@ti8w>{ybuaH4)HjmJKg{2t%_v71>NO>~5y60G00c>ny)Y36DQcLB^_n(tYjI(rR zRH!4@EUf5V%BGxm_P*}3Uj%{((TBS~A`d>>Xz@hK(Ig`3E96QcEW}fm-7=((xR(p2 z25MzRXPaf4Bz;**EWmb5DbZ96lw!Fa2?-t3w@k`60qwI(E*;Kh-ab2 zwwhg-eK#!M1${y&B*8_f$)Vf+V(>NO9m(5kB0K#i$pc;v`|Ts@Ae|P^k#jw#IpOCm z<6PAx@4jK{))DMvV$Iz7lsgMJ-uU}EfLIu;l+c1K=`(Ni^SrnniS|n5slw}tqkT9y zkNNC^nYD{I(-NLaIX7gkNY49Dbc6vW0Q*ap$4;%s%st(mLv;3dub(JVel+kc1Lusk ze?l!!*AH4miB&k^TrCsAqIw_r^4)~R_f@rTWeQ|Sgk3=*LrbkH=?|sl@YNO_gx&Oz z(xUvETRYcUZ@K*l7M9Quc5Zs4wL;n|-BLoKXHT!h)aHyJN6b2Xhu@yZt{`owGV2R& zodneCJ4bg4ze7Z%4=Ba^XwjHoTsEpR%e%6&9)*w3cz_-Geto>Y7g3xmegpStt35bdq*8*b=#BVv}O{UN9!Q(JfLF7PfF?f5DYv@ z(&+6Nd>@q(S1&}N8`~r7fvpB2olF{%enB8xT1yp8g ztHAJ{*NvdhwFIM##Yq*T5(PuSwc56;gjdTc<^e8ht`3cqbVLWjbk`9B2hMb|>%qqL zW`-UDBX3zZBe6!gm4PQ1Fd)dWX5}aSf~r9&=FRc`;D)%xhn7dXLu%wxPo&D-!-kiU z@2D-%=#slDX|Q^MVZJZQV)44er^q`$>7fdk?41vRla_+LkK%*_ZhU*lAUpMoGunu&Nu)U&4?Vk$k+JX zTdzbHz6U6GunGiCp}%fA4*PWE)yHrz5j9NWEYr=5`W<#uR7=Z);krg3rUKUZ4(RCx zw~ysP_vJ^MH+y^h%AWTJZS2NsnGU|hoH*|^PFSfP<5w*(#AX+5VY^x)HZV3(v2>*8 zef*eBS#nzv?Cc@%nv9%`Tc-T2Q`jZa9L?CwN||mIB&St|bK6AhAR_Sd;^QsZg1jwX zGj2^5{ies-_#{akt`WM?S#yW&!g!k6cs5U~39k~??xXW(ZH=uax*gzpsLkrTS7t2} zeL=jW(mf2NMH<&sH^_@#7AXrJF#v!CI=00LJY8A|6k*tf%nAJD$Z-pyTu-NxZA>)x zn?pL#)gU-sww!a?pH#?(atM`Bt5MosU7+~rReMgnh`WrKdH>o!a}=D*2*)f;{1^@W zCI#%i9CmV}6?v^Nz5QyT_(|&M8TwIeVvn`}!56OzXLph%Tw7j8Nzt^&DpghNxK1lt zqg;b1ZoPfzg=+TP9B4$UY?1gx^zG~R)41}{>-TPqUYf>lk4JTS6>2XF$iA;$uOK7k zTh}SAdIFgUHtar+wKclOAz0fHK+65}`l7fh9s*hCe*;{5$G1eL)BrPBCUutL>PB`a zncccXA$@@!zGw==S_=tf3szV_mhD%^IH(Q(oavbWUTLZ;N0H;ln7B_#cfU=m#z%xd zOn2?rPY~*U?0Oe#a&O8nt29{t85;Vj-08hrvJ#$(Hg~!$_Io)#1feW$$nMC2dCYzd z*A{!O<2P6?kK)_{6P7hIS)t4_wzNJEAa1ms_NxrAV1&drvzT+Gcbp-XS@yHX->1fc1b2W@w~@-~e&V#7ae)Qs~}JI^M0g7ZC`+MgjV z*9rx1!1H2khqjoHBw_sk(RzKw)Xuy9V<+TMrroi5Oi165mUH#-~W26rGTY zioJPL-{Dli>2kmSV3jsXmTtB_(ZROVTsF&8oRV&!lROMA@^s#L3HE1tv6wHT!L$Fk=$3!CHEgN?UdJ%#F2!g{NL)!ze#x*DJkD1W)j!&arl*Oh*;2tSMI zWhS;&X)*Onvi!VfN?e!MF3h=_snpJ8uq*m4bTf6evU)-&@mjMCC?T7-D2|9NnP)?& zDPY4kMXGps{X6Qa8@0larlu6VK3!m`DXRjh6{i^)yA{?p7Mzh&~`i3ij2`-nolr)XN9@ zLbF)E$s41jgU3pa8b2~zbqzd6K{TddP|PZVi?i=d=0-e;cx|y9G^~xAynuwhFMmv- zKjrowgZ$*Un0eJ6)#`4V(Au{kXxF*sqS8~;ZvludO+QE4K3p6;j~RbrL%EYztzb%{ zdt7GN2M57R%{c0M6tml$qai?8Ny8N8$kY~@@%r$g)H411XT43ql?EGMS_+1+HVm&S zbxo-fB}uIU6-R_yoKQDVgV6(P5^ujd2|Q5=TJ8=_AGNkisO`gy?2G1(h|aYc2BcbS z+2lS&IL>-^j*fsUmK#ooS0r_<^dUiNP;|AYH!TU-kDg<7WsIqa52YyO`dAtZJ%#LE ztC=;20DmSf7Yo$Cx5r7-)XiQ~O+R{(MF25+npb(rcWiS&x2(H#Gp2x_eNv$fYx6^% z5Ym!hBC8%rkZF2q^&2#AMU@r&ydxJ)RVg&J*6GBhqpF@lDRM_in01 z#Ux-n`XM`kK&1*}SKBIF)1ruNp+Z%aDhzw!(I+P?$tnu~W!QXuTYad*2W{_nr%_eu zBtW(&8V5Ow5FF%hYsPCqHQl)4Y&_Aj&3(2LPX=m9eQCeO5tBBoFDBbjM3dr?hhf8$ zd9U1W3+q;y(;DhF)+#P0U*uFGR3KMROD9}Zm9>Z$y#>orsK^OfQ7C`-Y3K>OR zHScFvF-`|bYe^?b;!HoGuP!@SVnW|yN-MQoDev*QX?=6o0*q=q6V4*F5c<99%N-L^ zjzA3FOir)qKRRl7Rb4X7u7Hcz9{#q)_ojq1Xy#}^r3YQ$8_^>!Od1S%8O+uNardZs z4SXHDsEdclt;+IMJnam4cplwL_T-u?mlURRJ^r2zX8r3zZ1E#wu^Y}k9wZJ zTcbYQrQ_E9x>px6JK)jg%V*3v`0^w`m*2Mh@lpk&3F<;RCU$9rP6iTD+8X`QXaLjP zyIwxNOrfABzSPHMEi;fDlc#w`=Zcl|qFp{=Q4%=9NKqubwG*~`9~MS)^Q0HBzR*59 z<|gJ?Q1i=Hkv-_>ova^-}WB3~1h zvDiD*u(%gje#8Lg1ju47QJDMm*oMnAvYmiY#pXWj_wTe)12$LE=SW>|5!90zD%27Y zRZaRtcdMR#>HwLlv!0QbJWZksjatE~$mFR#tIAsW7>jHqvBG{kduxv!7+%Ni8|-Kq z=y=*DUQ62eg@uQt&)((n72&(1?;hGLUxfK*99KPCr@z>o zJ}@SwTCC{!e0$5W1Wvrg;rGN^uXnb3YMaB4{^;Bxe_(ZJAm6R{!x}da-%)(|sof;m z7YTj7G52LT?}Zd$6xvgyNg9(IvO0t9SMydUN0y{Oev zWuYrB06`EgYn8W$Oz)4&5f)i68JE`wT0(RhAKDpW<760aV-qKBzf4NR*)n?gXzC_s zfJUQ($m@W}>~oIg8V*g|gDDk%w$2?DnQw1w({*rPX}(9nI)u>*U~*{T&*Mx#RcE^W z{xEbp7f-7=J(J%Ym?*7>z8e*~GQ2%qpFt9zDEmCLP)(YJ1Dy-EFhLci?oicyngBei zK>1y{qlZ6x=r-nAPH?jp;30EGrKh6Q=L~`m>qV-E3uKd|_?K@dW6u*<^vW0JtxxX^ zob0VXr_>-74V$&pK4^}Lr2Lo{pc{x#Sml#i{6GMCqZz@($yg`ej4sg7!BUZW8?2Tz zqS0G*)kYOaGE>Ry(d8f8w|RYV)mC?VLf@j8&AOLO{ObAPlSu0xlGopwNT~;iiZqMa z9cODpV4mph-wc6$fE4?eI<={nFI6`9yZ3}@IiK`{#~d-dE_AP?@6kTspgnFAFMcgg ztK$Ay0`x_{8tkwAd2A14{b1kE8I-*Iq>VHLV{X%821iSmT}`Fq@)nC2BfM{EG`+-I z&ll>ro%^V;wO})?V_b0>KciIjYOO5JH3u)Hz~}~o@Fct>DdFS;_Xbw(JWHILc?o5k z(M&TsD~9MnlHwNPV18xFm;E%bd-N2t>fIHh>)SPZqC|QF1k*xM?%uwkR0WY$BqLsp z5qS%)qne{0sY~}nx%&*CBE|!>m!vI2Rbr|OvcG+X_NYxfYyb$#lrXAPzn%9hkJZym zICO*P%<&G8ZxFhz-|-XG3*+%6%lS1qabXD7crXoeO^4CGU_S0Uybid3y@FMX-nUHE zTvEzF$M`DRVkG)qCG?noLNSppfpOUMUdG@yQa-W8BYlLEwM&zVPt7z+3d;O+I9XCT1{eUfTWI23j(hF)yt;n=C-q zR@lTGCgEmhqUkmkTfLPZ2Ko{SPt=E!j^NhnKvx8nOyx4mLKHFJTU3tjwIu zKqerFk<8Q%j)UNAWA~B_$PA%{4{2v?%B2KH1^Z(__!BR!xr2i(7YmECvoo_Zh}p)@ zj0MQa$;kp>WnpDyf^#t0yIMOyU6`!xDdF?|TnJ3#pJLYb%s!OQ#hoVG1Qm|%*kfL1O%FbnE>#M$;23B4B>zn zaRN;t|CrA9FU$O8KKLK-2|;i@!0))=uxG}OMkaQ=wBiafWa8#F_6~ob6_If=vqETD z{(Sxa)~evP`S)6Y8}v^#@W6SvWZ|GdrmiAz&^A6+0FaXj0AvC{Q~&@jRt_#OkO2VX z0swee{>BM6K3r57ex@w^jM@JO(Z6v1MbySl1->Qt%3U#z}pygAw{>g3phczr=e1F{hlwRI>ll_1_!lU!O~O(E}ubcUm#>xs}`(2iU1C9put1N^S1TW$Fl?G({ z0h{+L4aE8b-|kl$5XcFy5&0VpKJ(vc0Ja}sg1_(qK&+6zuMfZu;P_1z$O=dC`BfGO z1Oa}d0pL(Rf8ztN1L43wzsdqQ;b-;!jRqeN-emkMADs4^ec>km%^vXaIR37CAOHmZ zeGc%y(K8tGo9;nuzrPy<@&hC6$Mw&>2FLRKfe!c!4af=x{q`Q9-*v#s3E}+9cn)?@ zIM$FI99WZ#MH%L10^j#!a12r#IC3bw07!|9Mbg^ThU|y8!VyI!MaZ;yL_kep}V_FPSKsxASoq{oXEb(S$D)61yE4@QcL+EgpKWDm_uCZ%YaZm#7 zc0d+-?`Po$m($p~;cha~mv0EKw0gMo<*EndsS2hIFaz=K1R-9yw;C(WK4!`t zN`pG0r_@xGTDZhmeXb1-xL}q`sx_anr>1gZf^isApP9-0u zE7;$0mdrX|$`?^^Ysm=DrPEjU#)C+~1IW>Wo?Uu~@Daw|c01l3yO#qqUNjxnE|l!PAn!NEk6ZY|?@JfV+7# zXMfbP`gDSUcqzEX52cIqg=;)njvQu@StKbRS^^xY6CS*-wb|q# z824+|Y}115&P5&G*eN~%js?PWv^;s+5VIxTV*z^DPZw}t$3{Ar4>1lD?X~DrD+Auxvq_gsBS0PBFcan9Bnwp)Q^k6 zFKKJVtmw^N=R9gBGi@VPE*$MnFb^LdvF@`~SPDoP)Y2z>-sLQTAOB--r;M((mHPQt zepMY@kHtX^2C9mEOlQGNV)XFEtWAPJF!SpV-13GQLRs>+BW8MacbgmdvbOjqi9)Fn8e zdi9`C>4xBEYqNyE;%6=xD~%wF#Fk)<-_lp0_{1vvkY9(rg*wzUi0&wKp%HMw%8dlYOcmqZ^-UJ!S8)(|13v3`(DvOX{oVSJsG^eUcJtv{wDJ z#q@b-H+g;xemqLPW->OC;}+SoBeA}-gR&ZVO`UoSjRebHhDi9i#)jXr&O#ueXsqub zv_zfA13y{vrsxTl3~?CGm`*RfJTP*?mlL;+@O@cH?TW&!_*`GQSmTYFkjes`bqm|9 z35H21TNp#=Gvaea@DC_wfIsCV9$015*$9V8Rl{wwQ84LB=R}9Y-MH!ty)z0nB}SU0 zVu!zrNp&&{x|ag{_px5Z=nx$RmQj?iR@cb$b2B{-7WI@aPIjzrU)ZH>V+L7moKbIKa8b?ylQxQLqWOQ0>p_QJS za;OAxDX&eE9DBHW`HW8s$+#9_Weg^PP4 zsQgHjFFe6Y<5?xc#lf()C1u&QF^|ciZWT}lGP2-HEDuX(vKlKz5S1kMPQb(_XBLgk zTkCV(>n;0m)M>nX((M{dfNMZEz zQZtZfd?Z1E*Ttia`@xTvf>)E}{5_|Sn*ldVbdiStv8J zto|}tk}%^OFLP`P@P}{pGQ4RK_+@y0m*~;GdaX z7IxpSs>#+4X0F9_VTl}p%V)zDDEiEqushj{kzUI?MrHctx;M?V>1di3uv zPRFW#JoXzrePL2@ymJgSHGy$;edRPvr2kC!%Fz2}?EFNyD^XI)@z_sWWCI>^dV{BW z?fAMGRo7LiDm`(BO^9_^-j+$hEs~CpmmDG58^%bB1E!xL*YNQx!*qQ{yE(A@?ivxG z58=}#*UB_MQOICd{SZxC`6ek}j(k!q2!#_*>*de+hQ${C$xz`zGau#%Xo?l=2;TkH zv_KHx_%>tzG+9^w8LCIURvA2wTB<+NlF)T+xxwFLdUsFJqXn~Lp}E*t>;(`1jndQs z_8^6w=(LHiz3h;R+^U@OB3xoW6jm!eQatoFv3jh6J>~3`woz&S;a9>QaT&_w1dO@b zdzzK9(C^uluS99ffTrX}w8YrcZ0={aW$N7D)lx`y+frup`vD!Tsn6lehyd=70g#E^ zRkhhZ8@h974UtZVPPC6GIC{}%ttj-huEfaG4Oc!{KHg@r4o7N#rp?R%$b*aIsL_el z?WGQ~ts2%n?$js#&yWo)FTs!HS>G;s?=&2(-kD!)1li$LaK{OsqMFiWd7@STO(tqM z529nwltu`xjXKu<0XjU86w406}v>Gj18dSsiF2?OV#fTSa;&gA4;UE?epGdyi zd+WX_1w_#jMyy$f0E&}gdh1NmfajTaL=X3PTh#0fRxnF9ch|%`Y!W&?LBQjalerxL z1f>Vk|Gp6wz#s2k|A+u`t6w8Z5dl@e}&b>8dl!Fk#O-}$eYXbpyE}%A zl@fB`K6e@;=VE6&xT)K`J7{vMB=q!9yI=U8(YdhxT=!l5$jAh7gfVMX+j8ZC6WUp< z9X#|I*C*}x^sixgN`;~$9{1DN$1l0iy2w!VF-ublD0oMVWVE~lXD5yh!dFGhlPWYC ze~8>=-&P0sd#H`;fj6`{<3Ak37lLNwQEKg-j^(EWvSS>-#hq3%4CL;8{+Qvl3E2K3 zVT(!ba9Z&dVX*7r;&NWkV(}0YBM|Nq=_KhpWQWIM3{q5168PF=QI#D3G)mbvYul%{ za;33=3J>`8bzkRQx2A}Cko`m$ls&~bR}*}gbxImVJ~)asJ>EVzgxwK_%@Y1mq= zKf6A1T5q<`6rcdUle>^h)CfkVu=jez1V=DPcIb0%qLKiYsqIo%l2M zz-B+Su~w0zfuijEoSY9Ql<@b_r*J)Tp0e1YM3IBCHB_M z+7ly&KFl9C9^GQ(zPT-&eR_GPiGKVZSf9~X4lS8UK4m;%t`6@Jxx7NV zkq$b{2-_9DkoCjW0|$dqVuz4K$fDWEmVxzii)buE6JOsx_hHhdrn{IT)~)}fbVP45 zev6OFDdW0R7{6O|(4YW^fY%6#(#l%HPin!9>tJ-(e5Cucnbz}r(!z(6lsV=NBSKSN zt?$U=nhZ8E#p?`Y&gzVlMz*QJ@wNzkE8VUj!XU1d%B_9vPSO$&9V9BbZ7 zR<3xJ76kCLmx%GQi|+*wYqSpzL>Ql0L3Z>{v2!-3mx(?|A;_`&AH^AcY{^GmSqN@g z&{Oo?2#h9l!*Bv)RT(s^SK|-`bvd@Tr@A+j2pi+4Tba_YNr`S@5=adqfL-kzgYzA+ z(PhmWOub;ciu9B@UwYRL@5#R-N%*#r=LP3|>yw8U!I0wFaI&nI`qji-5{5VP!UQ8S z#z4CpFD{f6SX(%k*bRG8Xc)GmV`K}MO$>mqjcYNsJ{Fep2HLTsVs`5hT{M?0 z`W{dgrYZe4!`kFIxl(R5P?DO9Lgu9A9jJ~f#;0w7Ub5I1=^|JHG69(pEb<@{@ZE0v z0jJoena{iN*2FVi+mJ$jEf8PoO;05fO@&Z84;|fkomeMHhoG{3*NB$VR$jyJv3vZqGO?DN_wN79Vulr!I$Z7hce$nEa~SJ`OPBU+Ce zuNTK5^4d}O#Tn?!1$oL=6B+}=nka2LaNiPfRV*e{w-Wt^nsQupjBl&bz=<%N!BkSQ zs`^(%8q52h1uGU6Yy%bRD9UfUS`H{;eSI76`x3@&QG1cjTlIcYamIw%y41k`OMH>M~--e>SDYPt~%V&&rajQ zw98r=zw_nXyO`s|WHzR_Hc}!&<_U<}F^>lu$kFqGZ_O$!Ysk>$j|!AT&|h zg}Xe`T8>?lyof6ZCVoNIsUN0BJoV%~MGmlAgKKvNzed{FKWAwkUWn8JcL>4Y zu4Py)0!mBL*tQYIe~OxDgd5>%>nmEVrdDkSWs?0Onk>TZDH;Kr7{ABgBy4UdH|yMW z36NHpyMJCPlA{};XP}c)i%k1k)j>Cy#8TraY!(rFOSlC4%lVFxl$Ayc6I0~WWjlf) zW)hv!7j~o3H`NJXmJp#@xcL-)c9KP7Q@pEz;HOY0g}ZPo@5@)=l+1)OPU8Ft)LgPJyS&Hio}iczKMf59)0r;DDi79NOD;%=(1S zl)kdt&YU6Xx)kapfvN)`t(Z(a-u1z?#t6hMkn-oN2Y}~##{fw;Y2DZjf}tdIbIR3= zOTl`r&SQt4u2)G#SY?t0N1WQrB;UCq<_Nt5-Zp zHgj*^yiWHr6z`beg?|*sY`k@U>nm`Kjq#+!{wrG}A-biR!qt(luWLBYtCMb&@&a(o zO!14vl==CWp!F2UGkKjXUo0$$(?qW?oXo5ySP*)rI(O_4QY{jb>$!@Au#pe$hB;T* zER{Z00DmgZu70Pb(ljAg?F@)x0@XTXzruXMjnnYWZMXLgBb?83mP z-z(jF8rY58i1g!y>a?L7BL@*=Bj0KGr5$7nzs}wDnK|%R(KEZXy>t%LrPB}gl*ibw zbUVuHj=}Ekd2P z?HKffcz&>uFzZx42+MRA>ZWKB-GlM>;fJN{W2_$yG~zmjkU(&UWw(ce;UC#(d~8ir zsM)}B5%4g20Qp){<~o7Bf-063{Yo`PF-?r9O!&lG25qNI@_Kb{cYZAgMgN*Q?`FC@ z+BZ7^tE7du#$({lT14|>-OMC?o7k65SgKE|M<~-+NcG2!x)2fTV|kSkx=@C@WP`m; zZo@8M&1@md_SLnKFg86OdKP(}HL}6;y>b;KX1J9aJ^fJuB1_Tsrlj!H&vf*}@HM&7 zR+xl&-Pj9_Zs%Heg#Ksd=BTuV=JO= z_kJDmBh7c3&qh-2>kQpPP(TDL&ng=ZWj14eA}q_6w?k>Ef$Ha%A4fo>D7%?_EQ=`? zZg_rHC7Z~IgeTiOs_{XN>eq}`Y)9uw-$sDab~ zB4YbJU)txr39_VEZmfIlS$9z1?Rwh@wZK=j23l8pAV+0)ju4Fly10>(tk_Zry>tqx zvOSwlJ1WL6{H$Y1*!%M!Kkc}u7kpIh*+U6*;numdtEmu~D*H)qmhbAJ%6ygQ6{m%~ zQ8aky>_gEadsgTnj&21}2FNej%DIcLkAUi79=)N+E|X1RZoMui*>f)+Lg5dn72=w4 zG5@Mqt;`(%w_4@N77YAX3Hy8zM)jG%e@E|!Odt)KwUf!tdehr= z6hQlnfueYXDe>q*QX!C#%sBQ(owz?rSgqORX*U8ZZ@q3bBnR7~w(|X%QmxtZFyIho zAKk-)oy5((j5Pmfbo}V|;poMb{)eW8Lm2waD87AN{A}F9|Imc@<5bi{J^z&dSs+3GE`9|>@6-B{6rL)K0 zP-*3(-VTRP>TYV2Rd`z}xTF`<2!!^;;9#n4ASnK@t2MN6Pdh?DPBltr>9vfHPs(*F zUyF|}>xmc2`s|GPT_^bEd)|Z6@*{4i@^M7bx6_cw2@WgpX3x4-hKwVnEM1WPjw5Yg zkBM--s6tniTKW6W2OPNxsZnfjw`PrKv@BUTzevan_katP2Y@ov@~MPsLh5CUcRJ;m zTLt0(_gmW81k0=1x393Mx4j&^+uh~8GBoy2=5c6b#hw(}RvC#8;XRJ=k;Pe?$WX$|A|f&Z#Z`$UX!hHF|SzF2~w^A?rKe1e%& zn?9z{s-=a^zDsT1BaXY$Dh1O`phPgsTIyrz4|HO#xCKY?#$<%qR)~+Gm*iL2dp=ZG z9y!X;&%7c!oBq`Rq@3hTIAz$p$z!92ik@9kDko(g{g)4(6@oguKJK^U*tp@+3?*s9 zC|?1&og!m48%jeVB;f-U_s{lTJuOMWXoa@N??t*dP0Kj~yu)bq-+*T_O z4t`SMGy!meXIXBA4KhMF=Hyx!boMgUiMRB>h>RPjc1qoOxqUcqEK%D1m5S=ldD3+r za-I|pK*LN;a+XJR9_}EW>6@3cM(oA`Y2eeC$p}=Ukt6XBpcP@JVj;=X&jwnxoVwcf z#yO*p$UTt3TJgDy;G8HFVI>X>!cx9(ukOkT@$exZNDhrpOvaFTA+|w(zNNS>Ct5q9{1228O3;u~pLjqu)sW-+I z44g%h?Hu$X!gjzbeM`mYEE^fNE6@honQ9SRd3|fk7X8pvTCTU*DV(75Vm+g>7R?-w z2250z|9q{vJkASWjqFEF`&XUv@kBuCpbjg|W>%mALzff6uL(H^EJ?M`vvV?(Ain<1 z+G(LlZ{bPK9C#RY*|CBK>g)^kp0_a8GF<;7=N{*4e!k{<^p%wb29<6V6mzZFEAeIv zEY-&<;O^jeq}U{T_kCGO3>TZ>D%6(Maj z`!;mYvfQH>si=TzBiZxLCqbY5u$A^`#zzw_=~^06$+bNX(LK@-Y2?naz-hp?zENxo zQX`n?1;hQJ_oqET6v%6yH#Hy4JeXQbqu&`y=H|cefM+@6y+VT>+zYZf>D;yK75r+a ze~v&fk>_I8Qz5J-e}%v6v}~!7{0T2-Zj!AkD0W+8x%_I*em7$X{b(goNP8pcRy0f` z*S{=O(mL7m)ZgcYp_$KEKe_+6)r`+GJ5Lf+G;`rdx#qX-h`*l4Fp~=_?!lzq!2C~m z2rAnU3(;wi>zNeAY)wN;oBTzAa{%XP z9?#_`|By5{G?JFA7a})?L;*>))7(*3d@G9{ih|w7p@)(wL>SbdfmpGwP2drUFL@{> z^^F0cIQ{%gm#1_Ok`0{Pmu~;eNN#O4CJf%AV4r@O+iA?fV9wY=tf|DpXB17CHiVt( zw@uMQwO3Tuvm^Gk*KGQj&gPaSz-4Fd(1;$9h(c!;2RbMi^MEA5xE=W_5|3k)kOBt! zf^nF8pL{{H5!6*&`9^QeuR`-?|jh64Pfp6W#3AgZ* z)Ah5nD+_!w%{@Uy$d`xk9)a?_pYWRPFE1v+@jtuZyk4wEzpQQI=qx2eA`O>*k%&jO z9IqczXs*7rz>?_*aH$mF&oM#P&uhRRTK;lUiN)IGnwP($ViJ@^BqPX6VIwvaNyu$7f=lzF2hcbjidmGFv?_^gSj4HNLgf4NY=Uv;*|!% zH&+-^*mhnj_oh6_EYqBIwXYV9vLXJVVQq@#n)gQfT{&9kP_0bTfH!q*)^e;ZHN<7r z70zs;p(9#y_DZzS3?oZ|FM3eteyr7?vE_+sOGrRZ&qi->rLc~KblbBy@u2Y!qK!{G z4#s1XrG@u&coou`8s0d50>wtEHF=LC!_(~0y)B-NXHsHT@Eck^;I_1ymrrLqC#ICQ z_m5|#0_ByKr6Cg(yDf=+&*QXpM?sWpNvAK-vFjD>JH$TKGFc;km^DtB1GLJ|0wvl4 z8!FePaN?4~#1*$8HV10@?E`PmINn|d@Yjyaz)uLadSJzic6wV@Ci9m3iZtV~@aSAd zO6HM5hL_t!J2uEfOkUGVZJ7kdRXOqY9#AqB9byaY?6*ZSWXvO7aAatUzcSUVzeR>= z4z1-gN0QkF9r}}`NlwA{xI2oTzPmw_HeCv`PD-s)0M5wKYM%?yaaueTG8=i*$>QhZ z(dI0MmIOSC8-s;h(5oW7r!u)MQ_OH zahfv{HK+WF($K2@i@yq1-%mE|;+UR)^IDx1N-nKHI}(&{_&PTlRM@{_16NL=#9pyP zDt>4bT3d)F)n99)DeK4U>b477u2xsKuzV@>%CnhbfY0W|=h(ZZSGG6?Up+@nbds_VBat+UZ2;9-?z)D7Z=3!7g%vE$R=Ur7;-fu^FD8{dNdC7h0RK-}AiyV>=)%s0#t#D13kW4faLVI>K#w`43E-7?g1OU! zz=>DvOo^os{6rWh(VxViApSp#3HPQ zUj%=${U3s02wS4d6JoM|ktn*GIoMkKi6zk=NP!5fb$3K$wl)_qhX@IQd7wgk0z4p) zHIxVVc=1?4`9TnVO97|=zd&NVhwFbQ$mS`F!>0{`3PYj7AORkrVB#y!Cx1igJOlqb zGCi-S|DE892g`pYScmnh50RS>1cgHXaE=WKWa9wvsybQ9nz>uC%L;>mAR!?M0zl~Fj^M9`g&@GkJopO+dVIBiRR%r|?Qw$sE(hfQ zr_(|Z@ZSdq0)qI2%>J$n0`vWY5Cj(dCkFkeVGtkmA4Wil82)sR0mJT3_W~#&EeqlU z3(10Hz_Rl4f&xGRSwTLi0PwM0FC+zmii`gLN*MoMuif0uT-{%}T3G`ggFpZTU}2F{ Hmk0bm for nitrokey::OtpMode { } } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum OtpSecretFormat { + Ascii, + Hex, +} + +impl fmt::Display for OtpSecretFormat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match *self { + OtpSecretFormat::Ascii => "ascii", + OtpSecretFormat::Hex => "hex", + } + ) + } +} + +impl str::FromStr for OtpSecretFormat { + type Err = (); + + fn from_str(s: &str) -> result::Result { + match s { + "ascii" => Ok(OtpSecretFormat::Ascii), + "hex" => Ok(OtpSecretFormat::Hex), + _ => Err(()), + } + } +} + #[derive(Debug)] enum PinCommand { Clear, @@ -700,6 +731,7 @@ pub fn otp_set(ctx: &ExecCtx, args: Vec) -> Result<()> { let mut counter: u64 = 0; let mut time_window: u16 = 30; let mut ascii = false; + let mut secret_format: Option = None; let mut parser = argparse::ArgumentParser::new(); parser.set_description("Configures a one-time password slot"); let _ = @@ -740,11 +772,28 @@ pub fn otp_set(ctx: &ExecCtx, args: Vec) -> Result<()> { let _ = parser.refer(&mut ascii).add_option( &["--ascii"], argparse::StoreTrue, - "Interpret the given secret as an ASCII string of the secret", + "Interpret the given secret as an ASCII string of the secret (deprecated, use --format instead)" + ); + let _ = parser.refer(&mut secret_format).add_option( + &["-f", "--format"], + argparse::StoreOption, + "The format of the secret (ascii|hex)", ); parse(&parser, args)?; drop(parser); + if ascii { + if secret_format.is_some() { + return Err(Error::Error( + "The --format and the --ascii option cannot be used at the same time".to_string(), + )); + } + + println!("Warning: The --ascii option is deprecated. Please use --format ascii instead."); + secret_format = Some(OtpSecretFormat::Ascii); + } + let secret_format = secret_format.unwrap_or(OtpSecretFormat::Hex); + let data = nitrokey::OtpSlotData { number: slot, name, @@ -753,7 +802,7 @@ pub fn otp_set(ctx: &ExecCtx, args: Vec) -> Result<()> { use_enter: false, token_id: None, }; - commands::otp_set(ctx, data, algorithm, counter, time_window, ascii) + commands::otp_set(ctx, data, algorithm, counter, time_window, secret_format) } /// Clear an OTP slot. diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index e125f17f..6537bf4a 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -447,7 +447,7 @@ fn prepare_secret(secret: &str) -> Result { ) } else { Err(Error::Error( - "The given secret is not an ASCII string despite --ascii being set".to_string(), + "The given secret is not an ASCII string despite --format ascii being set".to_string(), )) } } @@ -459,12 +459,11 @@ pub fn otp_set( algorithm: args::OtpAlgorithm, counter: u64, time_window: u16, - ascii: bool, + secret_format: args::OtpSecretFormat, ) -> Result<()> { - let secret = if ascii { - prepare_secret(&data.secret)? - } else { - data.secret + let secret = match secret_format { + args::OtpSecretFormat::Ascii => prepare_secret(&data.secret)?, + args::OtpSecretFormat::Hex => data.secret, }; let data = nitrokey::OtpSlotData { secret, ..data }; let device = authenticate_admin(get_device(ctx)?)?; From fbefdd3ceb544647239b8c2301b7671a6174348f Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 6 Jan 2019 00:16:59 +0100 Subject: [PATCH 2/4] Refactor prepare_secret function This patch refactors the prepare_secret function by renaming it to prepare_ascii_secret and by moving the formatting of a bytes slice as a hex string into the format_bytes function. This prepares for adding a the base32 format in a future patch. --- nitrocli/src/commands.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 6537bf4a..41a8aa02 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -430,21 +430,23 @@ pub fn otp_get( Ok(()) } +/// Format a bytes vector as a hex string. +fn format_bytes(bytes: &[u8]) -> String { + bytes + .iter() + .map(|c| format!("{:x}", c)) + .collect::>() + .join("") +} + /// Prepare an ASCII secret string for libnitrokey. /// /// libnitrokey expects secrets as hexadecimal strings. This function transforms an ASCII string /// into a hexadecimal string or returns an error if the given string contains non-ASCII /// characters. -fn prepare_secret(secret: &str) -> Result { +fn prepare_ascii_secret(secret: &str) -> Result { if secret.is_ascii() { - Ok( - secret - .as_bytes() - .iter() - .map(|c| format!("{:x}", c)) - .collect::>() - .join(""), - ) + Ok(format_bytes(&secret.as_bytes())) } else { Err(Error::Error( "The given secret is not an ASCII string despite --format ascii being set".to_string(), @@ -462,7 +464,7 @@ pub fn otp_set( secret_format: args::OtpSecretFormat, ) -> Result<()> { let secret = match secret_format { - args::OtpSecretFormat::Ascii => prepare_secret(&data.secret)?, + args::OtpSecretFormat::Ascii => prepare_ascii_secret(&data.secret)?, args::OtpSecretFormat::Hex => data.secret, }; let data = nitrokey::OtpSlotData { secret, ..data }; @@ -697,7 +699,7 @@ mod tests { #[test] fn prepare_secret_ascii() { - let result = prepare_secret("12345678901234567890"); + let result = prepare_ascii_secret("12345678901234567890"); assert_eq!( "3132333435363738393031323334353637383930".to_string(), result.unwrap() @@ -706,7 +708,7 @@ mod tests { #[test] fn prepare_secret_non_ascii() { - let result = prepare_secret("Österreich"); + let result = prepare_ascii_secret("Österreich"); assert!(result.is_err()); } } From b35ba8deeb34e47aa56a803559f72c7747ad7207 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 6 Jan 2019 00:20:04 +0100 Subject: [PATCH 3/4] Add the base32 crate in version 0.4.0 as a dependency To parse OTP secrets in base32 representation, we need a new dependency: the base32 crate. --- nitrocli/Cargo.lock | 7 +++++++ nitrocli/Cargo.toml | 3 +++ 2 files changed, 10 insertions(+) diff --git a/nitrocli/Cargo.lock b/nitrocli/Cargo.lock index ae75d073..7ba73166 100644 --- a/nitrocli/Cargo.lock +++ b/nitrocli/Cargo.lock @@ -2,6 +2,11 @@ name = "argparse" version = "0.2.2" +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bitflags" version = "1.0.4" @@ -54,6 +59,7 @@ name = "nitrocli" version = "0.2.0" dependencies = [ "argparse 0.2.2", + "base32 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.45", "nitrokey 0.2.3", ] @@ -200,6 +206,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum base32 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" diff --git a/nitrocli/Cargo.toml b/nitrocli/Cargo.toml index 7611c135..d9d6ac29 100644 --- a/nitrocli/Cargo.toml +++ b/nitrocli/Cargo.toml @@ -45,6 +45,9 @@ incremental = false version = "0.2.2" path = "../argparse" +[dependencies.base32] +version = "0.4.0" + [dependencies.libc] version = "0.2" path = "../libc" From 655f11f2416d507cb85e41edc3d3b41f38e22c60 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Sun, 6 Jan 2019 00:23:27 +0100 Subject: [PATCH 4/4] Add the base32 format for OTP secrets Many applications display OTP secrets in the base32 format (according to RFC 4648). This patch adds this base32 as possible value for the --format option for the otp set subcommand. --- nitrocli/doc/nitrocli.1 | 9 ++++++++- nitrocli/doc/nitrocli.1.pdf | Bin 32165 -> 32557 bytes nitrocli/src/args.rs | 5 ++++- nitrocli/src/commands.rs | 8 ++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1 index 9ad0ff4b..09af19b0 100644 --- a/nitrocli/doc/nitrocli.1 +++ b/nitrocli/doc/nitrocli.1 @@ -83,7 +83,7 @@ This command might require the user PIN (see the Configuration section). \fR[\fB\-a\fR|\fB\-\-algorithm \fIalgorithm\fR] \ [\fB\-d\fR|\fB\-\-digits \fIdigits\fR] [\fB\-c\fR|\fB\-\-counter \fIcounter\fR] \ [\fB\-t\fR|\fB\-\-time-window \fItime window\fR] \ -[\fB-f\fR|\fB\-\-format ascii\fR|\fBbase32\fR] +[\fB-f\fR|\fB\-\-format ascii\fR|\fBbase32\fR|\fBhex\fR] Configure a one-time password slot. \fIslot\fR is the number of the slot to configure. \fIname\fR is the name of the slot (may not be empty). @@ -92,6 +92,8 @@ Configure a one-time password slot. The \fB\-\-format\fR option specifies the format of the secret. If it is set to \fBascii\fR, each character of the given secret is interpreted as the ASCII code of one byte. +If it is set to \fBbase32\fR, the secret is interpreted as a base32 string +according to RFC 4648. If it is set to \fBhex\fR, every two characters are interpreted as the hexadecimal value of one byte. The default value is \fBhex\fR. @@ -230,6 +232,11 @@ Configure a one-time password slot with an ASCII secret representation: $ \fBnitrocli otp set 1 test\-foobar foobar \-\-format ascii \-\-algorithm hotp\fR $ \fBnitrocli otp set 0 test\-rfc6238 12345678901234567890 \-\-format ascii \-\-algorithm totp \-\-digits 8\fR .P +Configure a one-time password slot with a base32 secret representation: + $ \fBnitrocli otp set 0 test\-rfc4226 gezdgnbvgy3tqojqgezdgnbvgy3tqojq \-\-format base32 \-\-algorithm hotp\fR + $ \fBnitrocli otp set 1 test\-foobar mzxw6ytboi====== \-\-format base32 \-\-algorithm hotp\fR + $ \fBnitrocli otp set 0 test\-rfc6238 gezdgnbvgy3tqojqgezdgnbvgy3tqojq \-\-format base32 \-\-algorithm totp \-\-digits 8\fR +.P Generate a one-time password: $ \fBnitrocli otp get 0 \-\-algorithm hotp\fR 755224 diff --git a/nitrocli/doc/nitrocli.1.pdf b/nitrocli/doc/nitrocli.1.pdf index 3f785dad24c226c29fa20f36025b2205a683901d..f0137d07345e328d6f0f8b697c8887e372c7b0ab 100644 GIT binary patch delta 14085 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 D?{{lm delta 13609 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 diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index b1099440..b5d4e816 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -327,6 +327,7 @@ impl From for nitrokey::OtpMode { #[derive(Clone, Copy, Debug, PartialEq)] pub enum OtpSecretFormat { Ascii, + Base32, Hex, } @@ -337,6 +338,7 @@ impl fmt::Display for OtpSecretFormat { "{}", match *self { OtpSecretFormat::Ascii => "ascii", + OtpSecretFormat::Base32 => "base32", OtpSecretFormat::Hex => "hex", } ) @@ -349,6 +351,7 @@ impl str::FromStr for OtpSecretFormat { fn from_str(s: &str) -> result::Result { match s { "ascii" => Ok(OtpSecretFormat::Ascii), + "base32" => Ok(OtpSecretFormat::Base32), "hex" => Ok(OtpSecretFormat::Hex), _ => Err(()), } @@ -777,7 +780,7 @@ pub fn otp_set(ctx: &ExecCtx, args: Vec) -> Result<()> { let _ = parser.refer(&mut secret_format).add_option( &["-f", "--format"], argparse::StoreOption, - "The format of the secret (ascii|hex)", + "The format of the secret (ascii|base32|hex)", ); parse(&parser, args)?; drop(parser); diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 41a8aa02..4e32ad35 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -454,6 +454,13 @@ fn prepare_ascii_secret(secret: &str) -> Result { } } +/// Prepare a base32 secret string for libnitrokey. +fn prepare_base32_secret(secret: &str) -> Result { + base32::decode(base32::Alphabet::RFC4648 { padding: false }, secret) + .map(|vec| format_bytes(&vec)) + .ok_or_else(|| Error::Error("Could not parse base32 secret".to_string())) +} + /// Configure a one-time password slot on the Nitrokey device. pub fn otp_set( ctx: &args::ExecCtx, @@ -465,6 +472,7 @@ pub fn otp_set( ) -> Result<()> { let secret = match secret_format { args::OtpSecretFormat::Ascii => prepare_ascii_secret(&data.secret)?, + args::OtpSecretFormat::Base32 => prepare_base32_secret(&data.secret)?, args::OtpSecretFormat::Hex => data.secret, }; let data = nitrokey::OtpSlotData { secret, ..data };