From 6f4b4fc99e9b66c4850dce9f5162fd5c078e555e Mon Sep 17 00:00:00 2001 From: MultiMote Date: Tue, 12 Nov 2024 09:36:38 +0300 Subject: [PATCH] Update docs --- .../documents/niimbot_hardware_interfacing.md | 18 +++--- docs/documents/niimbot_proto.md | 7 +++ docs/documents/proto/bluetooh_terminal.jpg | Bin 0 -> 54332 bytes src/client/bluetooth_impl.ts | 6 +- src/client/index.ts | 6 ++ src/client/serial_impl.ts | 6 +- src/events.ts | 59 ++++++++++++++---- src/image_encoder.ts | 7 +++ src/index.ts | 4 ++ src/packets/abstraction.ts | 26 +++++++- src/packets/commands.ts | 18 +++++- src/packets/data_reader.ts | 6 +- src/packets/packet.ts | 5 ++ src/packets/packet_generator.ts | 1 + src/packets/payloads.ts | 31 +++++++-- src/print_tasks/AbstractPrintTask.ts | 7 ++- src/print_tasks/B1PrintTask.ts | 3 + src/print_tasks/B21V1PrintTask.ts | 3 + src/print_tasks/D110PrintTask.ts | 3 + src/print_tasks/OldD11PrintTask.ts | 3 + src/print_tasks/V5PrintTask.ts | 3 + src/print_tasks/index.ts | 24 +++++-- src/printer_models.ts | 5 ++ src/utils.ts | 2 + typedoc.json | 3 +- utils/gen-printer-models.js | 5 ++ 26 files changed, 221 insertions(+), 40 deletions(-) create mode 100644 docs/documents/proto/bluetooh_terminal.jpg diff --git a/docs/documents/niimbot_hardware_interfacing.md b/docs/documents/niimbot_hardware_interfacing.md index 383456f..1ae41ae 100644 --- a/docs/documents/niimbot_hardware_interfacing.md +++ b/docs/documents/niimbot_hardware_interfacing.md @@ -2,7 +2,7 @@ title: NIIMBOT hardware interfacing --- -# Hardware interfacing +# NIIMBOT hardware interfacing ## Bluetooth @@ -10,7 +10,7 @@ NIIMBOT printers have two bluetooth addresses. In case of D110 : -* `26:03:03:c3:f9:11` - low energy +* `26:03:03:C3:F9:11` - low energy * `03:26:03:C3:F9:11` - classic ### Bluetooth Low Energy @@ -19,7 +19,7 @@ You can interact with printer through a specific BLE characteristic. To find what characteristic is suitable for this: 1. Find services which have UUID length > 4. -2. Find characteristic in these services which have `NOTIFY` and `WRITE_WITHOUT_RESPONSE` properties. +2. Find characteristic in these services which have `NOTIFY` and `WRITE_NO_RESPONSE` properties. ![](proto/characteristic.png) @@ -32,10 +32,14 @@ To send data, write a value without response. ### Bluetooth Classic -Use bluetooth serial. +Use bluetooth serial. The only problem is that packets may be fragmented. -## Serial (USB) +For example, packet `5555d9091f90044c000001000016aaaa` can be received as `5555d9091f90044c000001000016` `aaaa`. -Packet format is same as Bluetooth. The only problem is that packets may be fragmented. +Android [Serial Bluetooth Terminal](https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal) test: -For example, packet `5555d9091f90044c000001000016aaaa` can be received as `5555d9091f90044c000001000016` `aaaa`. +![](proto/bluetooh_terminal.jpg) + +## Serial (USB) + +Packet format is same as Bluetooth. Packets may be fragmented. diff --git a/docs/documents/niimbot_proto.md b/docs/documents/niimbot_proto.md index b7dddcb..f7bc776 100644 --- a/docs/documents/niimbot_proto.md +++ b/docs/documents/niimbot_proto.md @@ -53,3 +53,10 @@ WIP | 0xdc | Heartbeat | 0xde, 0xdf, 0xdd, 0xd9 | | 0xe3 | PageEnd | 0xe4 | | 0xf3 | PrintEnd | 0xf4 | + +## Packets example + +* `55 55 40 01 0b 4a aa aa` - get device serial number +* `55 55 1a 01 01 1a aa aa` - get rfid data +* `55 55 58 03 01 01 01 5a aa aa` - enable Bluetooth connection sound +* `55 55 58 03 01 01 00 5b aa aa` - disable Bluetooth connection sound diff --git a/docs/documents/proto/bluetooh_terminal.jpg b/docs/documents/proto/bluetooh_terminal.jpg new file mode 100644 index 0000000000000000000000000000000000000000..07d32f5af4ebcac6921ceb1a7ffe7975f81ecf5c GIT binary patch literal 54332 zcmeFZ1yo$iwl>-X3lbzifi#G5|+bQbrPhfPet_4F3Z>u3&Ua zxLKG20P^wxCIA5N6o7;P03gA0@UJJN@N$32BmG2p4nX|VefTfmX#aX2AOgSV056RJ zcmmH+!qZ210@wm=42&EpSt(^~49rX@KLDL=;a{9=?7VCo9B+7jD}soC_?H?{;BEch z5+L=-lfTxE@#?pNkN>LYbAWe%rzj|>D9BGyQBl#*o}y#oKf}bpz$AK(hmB80OhHaY zOiD^g!$wa@#X?O=%D~IW@`jy@i;IGuUzm?Wh>eqr;}Kp70vZ|`CI%+qvuA`HuSj2U z{6GFYwgPaU0(t;ihzL}GC%6cRxCoD(01CJSk>PUwP1Jw+AUr`tLPkM-iiVB>F961Y zj~Nm12@)bQG7??qI0l~4`r@u)a_pW?rb&Z=lbqvljTCNOjuMSnrVwL*LH+tB_rvj1#ge*aq| z`+Z>lHLh6zCL#iS@(^(WqJR~foIn|uVfFyG8$a7aRK*{PD=MYnq_;k^j@7B|Zv69r zqaktnT3P70)7FHsllZG?&Qqq0&GsVc1{!1j8yQmQwANv72LAy|xgnxa{aReaUn%33 zT9IPgDAtJ$uYGn#XZfk3N|@iw#MWu^A%<;5d@s4lx$ioYyZPXGN5+HFc*hMp!};2t zi*m-xrejO$l^^NRR~D)?o;OafVQRwG->|VW5xJwvEY14bGny%R-&jfOqCC^h2Z*CH zh{VftOqgZi`r&$LaeD81EyTeRBUw>g(pI6D5Y5Dfg-83fk*3MQRxlP4pEY)wl#q%k zxH^LWzF~<&W0O4-&6mpMvm-=yW~#b&)Y&RrL?$~a%O-El+8>5GJ=w5?{SetcYg>Dn zwtBIEB%;S-Lu1Cjm7gcEmb1A89B4Kx+L+z~R$p7MNNQixyFz+#7b5C<45{<9deAW4{Wc7$c(cBgW}>7o_>lMQ=$afd!QjFT z0*}ModAFqgTxgFeM6|ks>=6LC4Z!Ly|HuE7x=f&MS*G}yH9h&4+9+ms9sxorXC*}p zu(3|pd&FIQLE@Ib+{{k{I$05EqQ8D6XD5md$&Nf=kpi`fwIhawN0 z9s%j{H&d$kAPYl57{UcQnO_J)8RAcd>=3~J^i=aX05MT6g22A}O_vP++K-hR(~=Y$ zL38HI8hTX3aaa9@hoy;6Z&$>kyz^k@lRm25_C$n2PN*CAj%v>a&^INT?Fhf9_ag`K z583-ih*D%`qW{3)7)&w=MvShDby24$wfBdV^B;t%7zGY=4qS2A;;t8j=9u}Wo?oq& zK?+mUqn8___->-VTJ`c7Vw0tC8{MfII^T&Dz6r9Pum8hAU&E*h5Kg1xpL#NG9@2j@0E6cj_bO zttB!=m8Im-@#RVzA>lSEvCs+v)WNnPMcbt`^`;P{$xLaxQQIhHo9>keECxjW^p_;W zE1Dm2NxOXxWrlTN#Y9^c58fd+8;g=G;f}Pmd z^bY8~A&z!TQa#{Jub{|I>soms^>LZMR&8Z~bd@~|==G2~s$f%Val({`af0pH{Ea%I z%k+KBr{e~9qFp(c19=q-P0=39l#t5Ab%$UZL^k;zR2TMYr{1md@v|S_U!lFa6PwRR z=Xp33F4p23*>&(M4)+J^H~Y2O)M_Ody4q^uJmDkUfs}*VGgulTWAq1aNJsr}>6WUW z{Tgz)d+-)*|9-;MO)`Mo;2U{z>(d-RZk|x@bt$$uPxw?n>Rat0pKVLT(ope22f8Ir ziGkLeLqww^Oj7c=34Qy5{<j5F#O0RAK(Tw)XzK zJzUF=JNxu^ALg@BjD8u1MJk;pw}WskVn~~s?#NrXc0rf=2C|FPjKjffu?X%FH%v~`7gDL-lwMZQI#$SN6M6@F92 zUfaU5Ad}|cK78eELDEUA@?2}`I(8x{@evT5i4iK)m!)O_AOkosdA_}R8BG(@BgH2; zBt?+;(3JZK7|uI-fGNW05=3!#jz7e7SUI6@y;{%~@BP4O)Wy5=IdCW_YQ^Z2mz;FRbU9PK=jkq|dy6f;%}k~1F)O2|$fi^m z+>J_fZ;qIr9m0Sh-iGwWJJO?}XmL(|9>Q80=3-vKM3}=*M5f?zb~IcExB5BSJRYTS z#Lp(<60{F#S4?_a_u%lQuGkjI%>Ke&w3y`lEFmB0=xAO0v3n)`MK`GjslNn10v*`f zrqJ?iVOEni?zznzl3Tlhm@t4eIz4SS0RJO`1pY_V#~HwHj_m&+Zy4$46VgAt;Xir# z|DX4U&u$sAn>%lg;V=jM&qxkDy#$xVHk2!Y;%e^)GVgBX= zrRIRbE7MsTCYRWq^rW(*POYZy;^Qmn<~nItj4KRc$rs$JsOW%wRQ#pqyS2o_9cfI5 z>yjnFTnXtYDylDHA5lN^m6_-%K(!l41gvxw&~pRX9j5)Pa@TjS0XMB-f9Rf+366*+JZ16 zAyE8$JtYrFUKg=N=`d&GII#L5!=|#X<_tw;C^*)2oH|)vq@~s2Pplr;tkn(`R&2OGu*NbG?CVw zJer2o`{-)rM%y<%T^gPt>CXgicNeuoJ(+_uLm!NzI|mAvVo;EYgYLhUwd_?r0yuSt zL%0{-wbysY|FBSh{j4U<>V=^Sn9i}E(>HwP>L})oyw0wSri5h|A-!k1r&{j#>(wgl zUKU&B$&(tF06!iNgNl${aKAjK!u8J)d1AWs*RNtEtgR9Js?3CJdilxYXEbN7Gu?(i zHcZhOt<>PTXIn&Pn)B4m(<$(w%e3+hDbn*R;*ZI*C9-kZ&I&or4X}2#1&X8D_{ry6 z06&}$3R~OGGHhsT4mh+Vl6)H?YeG15+tCYODaB%SUD>GDA;NqCJ=N*Or{)+arkEFh zSWDirx!Ac_A~ClfEp5tu83nPjpqTgNEk~S4=kR<0Ae6j|wP5|aqXpeHNW)eG#O5u2 z5y+@&xmKl-N|1=)GIM>U`pG!P1He3fVI$gk<*}IcB4u@sUo$_hE5EBCnt_PkbpA6A zAGMHS9S~`T#fQ-e9!b%P7 zmQ8Koh0FzpCx2;r?-q^ZRfyqRu^|pAl@V{N23^IEL2_edF^7w+uAP{7<%a+aB)KmI zjRxXtwaVV#_ipyA`>Wvs?&9R)XU@Q`P~gXyW?_SC0VV&D$R@Uw|Z!Yry4QEcGU#iliS1=Ib+2$5|v5$0s}{n%NSLtpIc#>|Z3MDoQQY;w%`QP3`?0 z&9fc>=u2HK=V*_B-tR5fMSW9V{Kalw?c8#TRX2ByEsM;y-JDl47X;h&JmERBZl~Q_ zvfv3DB-g|j<)oukZ|{tvY$M(s22sYiUzUmLJp!T;+eI&L9sxNLMsm3P^7OU&x(n?IufMY*24V7vvbMYA3pW|YhWgY9Y-qV{ z5b1-bROkjdvA2PbpIhk z&R`sEs5?fW{1z)o#GjkYqqU-D+>3XuSWx=@*Q+=twpBZxh^^$)J4Tz8I!!hMj_%B; z%&UV8C75>+quOPnh4rVM(`jvQk;84%r(|)DfERB>IlDx>nQj+cWvo~1W7Ibh_afrA zWpa0pyKHBh^V}UlLWbtmgZRK#Pls9R7TQqx5z9FE^Pkbn)Te!}YMOHLmepfD0Dm7& zJH7(S?-z5Ed{f~^8yzRHNU*OOt3kCz>qsaI+TD?b@&9gll1BG&DI)=K;H zDZP!Y%<=)7VDE~*OvLK71OgAMQ|o(e+LN;<)9qJlApS0gegcLD(S8_OWp;91+douY z^&?Q*J)LOPE$p0GAlsm=O45nK9XWh!b+Z6z+!@LXH?<*37Z)kGVtw^CD;v@ zyE15)_Yu%6|D>KsLbNXy=HBvfYJLj$#nXY00I%dH+w=8PHm1iCff3n?U~#9@I_A>@ z$~DxJ>^)6zO4|!!fnbqI4P@(B1mz@4aP`;ev{L%Ci8iW+!uR71FYI-ijMoHXD~yAzN$->x88PmOYFkz882= zy94vDs}vgQ<0O!jH|Ea~Q7ZnqV_8bFSQrHl`Aq{d9(%MGo!=ZvnQ^?uxuD$q}+|3yc1&YCbDfeBeV{~TjJaE-P6(kr;g=I$iJoxmm~WyHhWzLd~TKOH{Zdf zRPxhZ;}m*LpcCCIN=evl*IiUrYh$pyIad7$;L_8VsfQW0PPe#lUvAN#kos!~(mnmi zk|Ki?M*3U;#CbFJ``plqTVKAr%$Gn7mPq_sQc{waOeQ<`kynl?;>iJZxla>&m}+sU zrvzL((!8{LEeascr1f9fGuh?9z8v)YnD#xwj!=Hq-kZP9HTkEEv%yEeQLN0$>IDpp zZ8@|6)<=1_O2j?l92%PA0F}Y&8AVE|#Z29T?~Bk?&UM?Bul3ucXP$)LS;q2pzWRYA^kBw9Pw#4^E?`AZ1j zZQEG$qGSY{PhUZC{c`wFNAYJT)bSf9{KkK(vXojzQvH2>qME<~+no%wksp|8#S1d{ zRpnyE+^yUj$j<;vy;{pW-+U;oiCnpxz9=>7{J6)fcFj{WRhcBm@vt!9vrV2coVEPV zb(buXA4%mfs=cqhs@xR_=-OW=vZb-0AmdPQyDWpWkI(728440ilvp2?To_N_=*w;7 z6lD@V^BXxRFMx)Hq@QDM_nZt5%q*~T^ zz*_1lmL0M~Gc!+3I@$4M^ouMDPkUoFV$JRj2<~11om}E=u&(TXrx{!kx=GVd@S6o2&^N6|1^m5$iSU$iry95vgbM(1hQ?^ZR6Lsbv-w zb68BSyGoQA-hf#RPtW_gnw?7e&eq&@?&~0cHAF<;xsW`?|I+^7XBQmit{RP{?)oon zgyFw49VYmXfPWl>IYw5T%Kbl0aVA@!(!Xl>%YSd(+QctfUIz_!UM7ry&qH32B%!PU zw(OP0>8WFP4y~B~*&Zgf$!JD!R@DpZcX=G9WbP(6`mI|!?ncwGa6D^#X9zgjh1g26 zLneq%`)O)pU<Wl#f=s49L4 zJZOfnrN0W43ZF^;;I-5d9fPoqECB5i;PP<&O66Hep%@1qInB5-Lh^9DHf`Md=dK2Q z4V|ogV8$;7S8UhnF^%SqH|jsv-MBz|rxnTg2ylCYnokkIJh%hR?5Xyfg7WR?sC5fRWR(T9}BlZXfQ8EP9lTXljufDokb6H`E_+|ZK+h4 zev$^*Pk_K*+^O^R1pm2Li9!Au!hyxyKV1)=&!JTv+iC>|o+9r!*pwB>2LNK#uD0lb!D&6{qkk;(m_S}`3yA5!rQ7L4^{ zHuxmGF;ODvsyAoAZcFqHNkx=`l=bSrlGB!(_7VLxDB2Pnu_%4d*SB<{DHVfFEt?`* ztcKE5EbdI(RQ7#5FTANpYh!3!WQs*Ijubm77%>_0FXpm3088EFP_Ee7;9sG<^xMCK z^F($C)6nPtwd44IYDK?Ooq@HTcx%kdo6g|Z?YdCEkU6h{sA44Cork1YJLD%)7e|Ocf7k4LGm;9jRqwm4j$E>Y4cK*QTrlL4SJrO^V z;1p@vu`@9x@ATHvep8YoG_(rtJ{SDieXecfwOVN?hd(LX-xcW0+RUxHqbnRXRGro; zCXSanpSlUQ9&bnOJ+~5w`k8e9YXhRTZbYsJ`g(bw1GcxzXH(0VcY24-So|ZBBfHj1 z#%iVCtd^W&g3Wf)-@V(J8u-CzLm#BoUb-`=AT&qV$Hvwsfv*~auO#u3P)Y5)tI|e! z#`&dF6$e97lySf?H&1=Cp_Mvwj`XR;4ay5U#}Q)(gynTdrJ=eTYY~0d??dqU>qTcM zJwn}1SbTMYspUNpldBNXl}*WuDBM<%Ch@dRI9ka+E>6i`LZjK&#u+2Ui6&RMlF{}T zQiNrbma96R+HZ>oUu1kGv45YGixNH;p&8l%j>I~%n`))6jk113TXHi?CS3KSnBwu> zMACdFwI4q&6959>OQm)VuQa|#fFbLy97x&_kyQ)6VOYPy@#+u zt^}6?$;lGBjlp0yTcW2Ciu^-U5LBeILAUU(#+pQqIfVea;68!$PEuU0l@q6vmmAv> z)?C|j-$URoWo+u7Psf@t+HOsK3%3hQjwfMR?ijd2BYgxiH1W%QEgcb);U0Zq?#Xqf zOt!goN?X{eko#}XLCdUgr~0K1MR@fAp4@n*oIduFMXjSuT#WlW6xF+qV3J8s zbym{0Psx#Nn-_KwxSMtDqY?z$qz3SPR0IivMK`<-ABw5!G)Zr*E$dNZo3k2snJ-?$ z1L<|7YO2MOVf?uk3MqwbpX{7ea#b~Tm98=k2`a)np!lG@u44LA;RitYhntx5_ zO-ID-ZFswQeRyUVjHY@M!G2dYN46JJRx2?fgohG~>CqhNZSTeFUfH?M>;)lwSU!lD z91Llp0>dOHSO-g+P2hX`<$+7*Z!Gn%;EHilBwE=_0vc&61TDe$Yq|?ylh-znfVZ%` zM*s->5kQu6r@m7AfN`7na4&lA@=N&W2!^T-KdbB9@{+PyxwHBv6?9a_w#xLOlq2fX zR+v|@1{l05n1MY%FXkm`WN(3^OshE^0}(RXwCpNZ2zW?tf_bJoi_qV~5u}wA@Eep| zZxipMy(wTV+VF-GexVERx0xKO7u)hceS{fo-Q-8_O71~Qwu*G zG`r^fXrtcFt4CZr5gu4jNyM^_rDE4(nCTxoTD9-!?=N3JDx{QWewBC&4Y9Sp2U9)m zTB}RCdkqI_@SzmJ*5szMiL046Z%fZ!5Yvy6veL2+FGiy*(T-AuM}TIv=5vg;BwW;F zvC|&01u>d6KarDl=iJeYP;3IX;rCUr_R8wYpy5Y=6r55qV0_Bs+op3~P+fjQEwKCu z$e)1OP3d=(-%xN3-&s8ZveUtr7TqO_yYT&l4B<4s(zF)N+|W)f)r_zuG4Sz46GD#-{D3N{kS=O07QH)GgN)bsT|QNJkLUlwt9~QSRb?gBHDk&kJ$x5nsjR?HFg*@ z2wxrkg2JHrUXt*d&y*hlHTt)V3;|E;qeEx9?=DD-z$kZ|`kl9IX$B{+rE9@8;WoC5 zi&FmPGiTDDzBIiN+c~s6XpYaP2utKaX`h(+*7jnP;1qKB>0#ceoU8eb=!s(^4`>Gb z2pAnyEA4p%1Z+5gcB0^y%o>F<9iU41zMz~`3T#o*xjclc|25ttz+mngqzD`E%&3wc zN{V@_6TZGixFu*m?i(?G6jFUhh6>@uVJ%GP=6?>~kx6l7{MhBdk4O`lr>b~E{u0*y z?hzoV?(8({ac}v|=Oe@W)6g~Z*w1sRu=MM)AcD8*;TNHGA+{yfccJ;aP}kdPp6AzO z)Fb&(OxQo)Fp%WLhX2~4j}Ug-Obp^GI9CiEw>VDi!g25))#OFEMvQE)d6plF*JZD> zdpoAJV|b#*9q|Fp7nr~;-a8C9Jcu1)N_FhQhA`ek(8=C1())d2_SK0_?9QouEtmG} zwR6*K66{doC`p1aD7?x2Au@`ur}5ulbGay3?2CFF7lH=92w%k{2>9|4r5 zafQQH*$?!OfLZ5V@PR&#v{N28vX_DiAG+GT(Gyank6Vn5L}=R|JiQop&UnquRddg9Vs`tEuzd-(5Rk5 z0Z079zqTT<_2yY!MNp6Rl2&baPB$-M8o7b;ehf+CN@0iA{%z}68BP}mz2S+h%!?37 zBE7s)$8XW9#wJpWnNcK!^THO@JNPtVMJuf|C}h}8JoQuE*miK&3r9%;AMk&ZG_m&o zh6uvq_uCZ<979URFAd;mqWllNx1Ya1b$)}O`gti(d6d?jYp$1dRy=5~$J(h!2y{F6 zF*`0hx0KfY$9TPf;Tf6HH9}(`t&yX*Hb zfDF(*=n+sV^>_IQieKK6wMJ?oeXtqPv!h2qqn)-9}FmL!X z@DTt5Q~Ygymd|J9f_NcZ>)&=K=S~WHUL;4mqFBNNWSwyX-@Asdh;JwUE^oea7c^nz z!fjqsegIc|kw*ZWR{~!*NB+YVsi@s;xNUbSLHt7{Xln`1_IL#BDg9kOC+LtusdRcW zyRxN5@&4`+u=WUeuoV5Bdd#rE)oFqD56KK>6) z?f;PD@BdSa_CMPB0~dc_;13M^fq_3T@COF|z`!3E_yYrfVBil7{DFZ#Fz^Qk{=mQ= z82AGN|3Ae*+0Gj&$HET$;yNrD@?S_$`1xsjW`zkjn*Q7SHLsEp-=9W8j)P{5)%)>7 zeS8{28P%y1DmGR=!6NDT{-b&os}w;lXsaah^ztAPi#XA~EC8yo^co@2&R9LcwNhql z#ms_bLd9Ya%5)zaoKbzq%~b43ZDDc}kXppd?VQup#G17{p>DAz`egpvRY^nX9V+FI z;rc!W4q^UXL3Q;N{eX|U7FGqjuDETs9d_>c&pV)~2vSh4hoWsT_3m?pvlykL(IqQq zP`*kJL%B6n1aDd-mi98*kzkA}q0W;z3e+A+i74Mq2Z3xzVAb z!GRQ5P7+LU>6KfTMYCG#QS6alp6}>as*k<%PIL14NCk2ahJRR$7%7Z<-_eU<#u{#@1 z#AVlxmZxRBef{zpMG<|LCGk1i6>_Z6A<`3sVZ^ClAy@h&=EKh}Q*4SY#}>u;U!`k6 z4x!AkVP|{S>iqCCmmoVgSA~$((XUx&XCBsq&Cq11#wY|ect7!W+hMMLafq5{k`$(?rrbSQyG3~r^TmG&~m2RhqxnG(1 z)vQBHsk?PEPD5m;{){Kh(8E`w&4pB(+s)$Hyc1@khquZw%(~_as|(kiO~=nBU*J(c zH7%IAb;oyBXp}rXVS`C;AV59#gFRg@eYA6LQN?huyzJDJ*)mXd7W>C0W$jAHE>td2 z>e|uUgeCZuwCSsnb&k|15VaCLqsS~77vo3{K~ai>oSBuCryg|MtKa!)Z9@W%18$$6 zcLBK8v*G))LYaMr`20k2;{De{&|Wb}U?28k+kO{D6*?q8iqgMzSHvN;YR5F6?B}f@ z{qbuBhyS&T&F$;m&idhw>vJIX?9x1+3|myS{h=U)sFzHb@2Z%b_*&7k)S};IkeJ#S zCB8545#R)nAv)6456=zNJn0m$9xG8hAzWeeV3Rgn3Y6N=of$h=JGR`Z*bT*e^2YB( z8j++b{nu8$-bEOHYHoS9@Q1f~3h|7;Xc=$JV^4PvfWpIR_eLwC*AivTL#M?bo?;Tz zVo6GU20b|ULu+>ypH`o+l^4z_g0^U53uHpjgjyXqp|c4`D=vxo=Dh0aiMX_#N<^4) zIDF?sL+;CF6O$^1Y}(ZZp>3n_wi<)M=jxSijw?0+-SH2F1;b={#rOT2 zUm&(_G!?Dn@s6LaRq}MqPZuqCqZXb{WGocjPwxe)gx#s$sa;eI9OH(rI};q)q?ONJ z{#KL43h>FiRsGy7CjPs$!S(~#31kA(1Dd&b&p4{;0|6G!@?^hcw%silzDA6`9lxxd zVp`So4BaTEeL1Io=AuR2UQn)oV%AYADn8EogN4RD!-^q{ZanM)rEJcNsk-I(q4c7m zYg3_Upqx-uLRevcDfx7YS`Z|oT=rZyKL@io4K6$5_A6I^*4diSu zDC_S^M^AhQm59Oh>tJbdwIIS2)f2X=8*RqlIksS5v{H|nW&R=-$0&5(YxKpt;IeT4 zH}jEw#7|2esSbJ%7E%tmP$ax(hlh^oN-3uEAEXc_u!oubkd$t_AmH_bk!!jIy^YzJ zmg3SN`5+$3{?Q{A!qrq(QX|O55W$-)5y8!}4=1$g?d0FnkIwiE zIu>Y^-slbjiHoa2NxcuusUlDOWlnOnoI8tgqQYab>+!cX0Wgi*v3S$?eO;D%Zu-6= zdKWVK5y<{Px6SS|F z`%{{C7i}MehHNA^F?Q|s!flSbQOXIu%-%XozQqjCWV>V5kfw|B!6L~xPt54XzqIKFRsczUn>@KTqm5i z%`r1ee;0uhWq8roV07l8IoA=!;r4`HukUhg_4{dj2)OcSt(pco(Yf*l_g52HlWT2~ zeIg4x;at24x8K+g|Bg%ZxA##Z0^n4gZ$9CVfXw9Em#YN*b8c89rx^xvzfb^Gt{2K*6GnNXw+w?hX6B+=FNuaPQbnRuN}GuE5eG&NZw1BFruq zA+V(b_fwVqz+3pLdYxkY9e2==Cs(99t^(L*}CWE4P6p5 z8TWy9n2G}odP$$-oAHqqkHUzV@&n7sf}cNR`NxxnQJvop8tg9No#J!c_4dbX6BkvJkbC$$$<2#PHm&{0!=w z&mv&crP7UN%cVS;+}eU@&v(TXq|y2J?j_WZ%SB_mPb^_P@^4q-4P*#ldI+-}8#))u z6omybSJtJcyt!kg!zxKUC3VRSE$?IIhPHqwA^?CXdq1fSt?ju)sr+U8GPm)3se>*@+O2`ZW-I;ZMYr}%QM7xJ+Of$mG18aK zg1%?`_cD+*wPrGR(c^#xS)w?hGTreb>}U_q)yCpgVCc#T*=?v4kdmpWkouJrJs-^z zjoWhqs}*P`-@Op=(AB1IE7A)@zU@!xoDolj-F_rC4UYq(Q*#&S1At2|v1joYdNs8J z2j>=zB)OK+i!-|(u>-!%YGF~WVWeOD_pVhaTgJiqA!@D(k@aZ&G+Fwol2RZ$CJisM zpwJ%a+bOV5lKAgfoi+46TIPSk|0=Y;p}CHu3oJT9&y zdk$Ys7$-L)x!hG^)uFwt30HM9_l61gRy_T-`rl&BmC`YIKp#1EUA~{Tv|EJD1-}?a z9=;N{Rt@P^j(>-YISq*)NMLRA*e@T3szryR<3qUiFYTtoY6=bOK~-( z9=jya53<{Ci_bNDx-Dr{e=T3ambR*q6J3)VSWXROzoyY70 z%51@*Nqa+9k>u0WA-i6zbdhucZuKmjd6j~woOp>gIrN1Gk+K_H z!xY!9TE`P=#GS9-gg=R;;Gg9a7FR2*9u5{E8edKB#*p&sU_qVYP9r& z8Q2EZN~@`0T?|Fkf1C4M@@YSvPm|k0D)A27JFqy>GCr>i@SAJMw`;1<84OfiR2Ub1Dv z0<*45x$JgcNJ^q3m8_??z7`#-+Z!g`9(Q|c9&(Bi5W>wSYki}^zUAV9EjwmAo{`lR z@M9|=%cT17fz8T`GJa$H;)P?37Uv@%YwBf?tx3vi`j!jLz(I_+S1Ty0=n;VBWtHpZ zsZjUQhB_(a0N18xu7STFTS?P{KA3Bcf~+Qwr6EglQC0Skf2p;%+s9xr3v6CCe8H;} zTc`#a#!t-n^$1V_pA^Aazc^0dSaNNaSFm)0K__zF(6=f3a;1xU+69Y-IGBM#W}=Kc zkS#sk6U1&cf%IaV0*j5yA{HBx_(d@m8AAFAAMQy_ulL7W-_8qIo#%{%Lc^-fTFN+x z6v3*{rkRIs1&)Vy^-aG?y1Mw=Vi?`m`lY}FAu`8YtwmkgNPIs$q4ygR(nPZ;ys8-i zTg2Qq!uhChra3|Xb?vHTES8^>H#s)b^9Gkx6zVbn(i(lC$ocRSw=);YaJp>Wiv{K3FNS;n*8#las}3$s(_oL*$^_M)8{voe~I$zNkU5}y5n zakrc(gDR@hYI--Hj{bZcork57)BuFG721M3RusFny_Ox1X?hStI2?V4a zB-vFIgT|C8q zGQ7QkI&i}asVKS5Yo#RjE7$`8#m8vNqm=+z{9x&-JsfK|&@khY=n2itC7ODiky5`x+ zf9Mw?NE3+nDBUQJioN85ha@)QG{lj}^z2%KCyVA5WH6X2B&qrK)SQyM(v%mP^nqKD zi(+!h(EdrH2I;Jp{ByW>P~1NT$=Wwy!3N7MDp#GG_vbQ^6rk=hnwKgHi50ati`}AY zF=V3bi#gyr?uFO`!f@eKUth6pz&!&cc_y(I0|0>K52u9#xTp}LLNjz!3bMZtE1~tO z($6a&=pRP*C4>N&y29tC7o`NYHbmc$LF`qxbH^+P>YZs7EbSM_V^<@|Ef#4ztnIZ4Qai3 z=7$9MT{IQ)kcL?YHf(?rmvxpL~`Z~!nx<+Mff;bj;R3m zt+3b~9otFR_I;swQP?M?0FTpBn#ExAn3-4T{u7ATO1@#AjdtWDl)imI7(ozM1vX|r zNU*|X_4XX#jg0&$H41x0P69xO!tNUaK+Jpsmy5-FdfHELk^N*3vxiG{xNFQ!Pb5WhkFF6T5a`-|}Fjz!^dFX5GjVrB^pXFJ~ycSGv{BLtU=jk;kKJy&<9 zt3+jmds`uF@##b90-WfI965lg2I$fgc{QI+w)&i5>qW*t0*+re zPAEy(x{Lp(ApYMjr%_dvaJypg&B2}K{7KVu$ns&ivvp-J3FMbCYV=2#PW1JJtc4&M z*Uzd#a_{Gd3-Co~{qXZ^Y~|yvK_LYMq_E{c#6l!HpLmMEM%+TT@RrdPhhM|}zP`IM z%OEYiDV{ozQt4p7ZDP}8>Eaz}6Tx;eq}^LvuF5lmb-X z)D7f-f-=gOS(iYiAeBLHl4V6SNdC2R{;#Ug0|)wBp|5`LO;E-JpU8+@tm*L_Pfi7S zHXkD;wa57SV}AbPAi7W(E~D#cJ;=1eP~`AwVdL3_R#}an7HK@bl6Ly%zY_V?-(^1n za(7-PG%51kOHmY*dDJxWvd!&K(+4R|z`5YMM&I-sfE7C?cyccZoAR8ma$ba_U%sZh zbh~4Y5=kmx{&ZO8e&+u*RbMPSgz>isLBM}ka#}=guKjt!+6ZN?d-2|ZJvHF7^nFXb zH(HTJPUp_E#rRdU(n~hfne{&M8%iAU@^mi}kdavll_d_E&AQ2a$~P9lFXE(U(ZiOP zo@t03^;v#r@1~Z=Wy=Ve9X!|lTK#pZTDam{@D@4>?$A{>EsFR0oxn3?j{w%Bj5Q4* zC9Jq;OGO)J!?2ddaMZx~|0^49YyhSLf)KesLHL?J zo<%a~D^^^6R7-{>OV!~*dz6FXTN%P`N7Z|RRc{KdV}JAd_&%{b+2RIdLVCX5(|cOhP>d4GDQLnNeIMolHM7}6CSNy5 zcKx2ycu?uR{#+Ehh#Xc7&A3X>f#-u0)3eEeIHD;~eFEIoUhMV@PS6_@RD&-?JmZ!pG* z^Cg@)jTxPOBzG~ddx*2QfTRB zO*&&Xha_V6itml0y)Nh*H#1r@sfJdUrwwg;mn|`Eyqq7t88!cEYTn7N1e2PZr<7^E zt4u?(KK2Dk@e;D4&>5%DhhB2Uc_rc~)N$?=A2#R_*y`-rdZ1b)@JM4Lk_d6y!D_0R zz)HZ;%~Bg9v|!a8YniP55czEs=RB?sYNsxq{FrgLHQQ?AjcT&72|dkECi{J49sLf_ zPU=PWf$lrW{mVt3so}hHAs9SjGpF_UsF1qc{`K92gWWrjh-j%wo*F}2&_@R*cA+w`#gh_Ko{Mf+ouGZQqHfEvlRz&Ls%IyX90kTk|K*+$E+ zvYwy*Tj4N0nxLq#&Di>g?)+@*rTe1LsaPB8v5>O7v%Q0Ox;qU-4B~t3R8WxLPqH{0 zeXx7#DPq4^t+Bhj;!SBuoZ(3wQJg!f(G<+>*h8zq{?Ef1XBl3N75C__lUI zFsz2}&4q00|kVQlo4ecS{GeD+1xm) zvYD)`X*AMBMPE#vuyY#MTlD-Q{j|6Hzj}iC!aO}-+&QI-G&p5RHth`LrlR5x@}H;h zV^c0;ZphOG>^sIa1QczI@0u6C!I8Et^yg6VzkkggqE&~(L30d;o6`f_9le+`+1Hcb zKe<$=^yXCF;kXgVYw&1Z8jjpk6B2)!Sj6cP{SKtKqruATku#Zi#4+&*h*7)Y1`YIQ zhcG+#{jMng7)tg3(l!2*P5>JH7i6apJn^y6pD2fV{!91BY9ss6s$h&T7JEMxkp+3v z-IwJcmvNrA5xCx{*HEEHfTxH=<@_ZBt#8&vu$RNNSE4#h!qn81rL&5?m%c9dH_-&n zxf;Mdl7HnX{g3vD)Xw)_v@~dRzs1sRLRNckL8gSj0s&xMjP~_s?!4uqTo_zhf^IW2 zRoUxQETjh_J|nJlX4-kW`v~aYRD}W)H^vW+sUk^EMxsZ2D7Nwpm3sMUVmx9cRQVVr zdpceQC(soazK+>%fUA(2|}psrQjFV@>I?K59f_B&`C|7zWLOpi}lIl3XLF2B7GdIY>9D9;7;$|~MI z0%C8#0LSB*n<-v(eT!N}YT#k|2N}Ax$S7Bciq>sl=#Q?E9IbR^W=;e*gw))BE!?uv9YvG$N2!L`CtBlu3%rRW`cEi6O}kSxzBRx|Zd zD%ol)l{c1k-a4Brk#7Zky+GLKvm0MY(s@uVZ0xzNR`Iml2AAmvp?rIlpGHyavEw1T zT&3!Y&AbAK`8nOT*73$MJ7y-DKXwRDAtb@1(Ga9)ohk@h9(h)gyrXp`i|-<@cR8~l z>Av3et~WBkdWYCG2#g=S5vdYL;?^-gUp@M5eCO0S#tpGBcTA+;-pbQDlvC^GYjy>> zX~%e~kt_N4K?xi85(`$VoIwMm*A}|o+dU_=5s5z*B&_nAIut^DCTOE| zBlaCTIDXDx+wUw!CxI4;REo<-14dF2MNPPg-zDqPSx z+d@U-YyQeJMeI^o0zpohpVRy{E3;nrYUYXG0Q~(`t@pcb)ej_}{2rW+YTE2=@aCm1 zlL)3Xpa~RAex(ucS21svTB_UR&2QHa@ch))SG3jh1To|O?58wr0yyu5c}x}_RUZhp zpX$z7FdMlR7HfAt>yY(I=dGpwqS(hdtdhXr(FHv)>-g8Lg6QQF?Be zMG~7DF<%Q(S)B~K#SpZ^9Pg>fq(`J#RvUsZXQ+VRKuchFWNvcSas0i2St!?BgI_lO zcT`h8bdrsEpQPaxB_%M*$ZA=?x*80B{HQA~vPkb+u*_lUdN|Hc*eZcwP@O??kGJrT zNt&v$f#h$P@8vOB>m|r8ji@6g9^Of`j61uIZPrFDpiYMrD5eY{=y8Z2XunXK4TLKP z?pzm9$R&|M$o>=F5>b)kr(4K=W~8_WI`@6Jo5~F)vxie}Ovix-Woy;x-J8rw?3FKr z&6dJ!o1QJfwI_;Pk)#K%m<2j3IcRh^@I$6IZv;Op-*#Tqil0))){b5X zg2PLz_j;!!SOOV{`~h~-t?P)8smvFyaOfD$0>Qx3`?MgR!|!uYk;ySDbv*hn_phJG z?vY?5ny68-KTpNm3rqDdhRRs?I9It+*2NqGpLH<05qVu2;s`SH_;}ZCm2t|fn#Ru_ zq9=QhySo3--|0fW2p=r;+CN)0UWoYBvsEfw9WKw}GkfbiJNub8{j&i%_PYkcE@w4p zGKR&Q8Hh!3&G*|d6q$0}59~M!$LPL(A5$Mt^OT{s+~aFDhJ3`w^DmNLvm!qK%-;&R za#@aSy_=M5TtE29NAs!aI3dR()8ZDsl_FisNE1t0^O<#00l{dyBT9kqq9{2bDO_vy z84pAm2U3N*AaS=bkN>Pq5=Apm*g@FJOs6gbh9ioBAoSh&|6=bgqvBk)cF`s{A&`XN z?gWPb!8JGp*T#YbX{>PxbV35bH9#P^TSJh>HMlm`xVtqFG-yt*{hhtn+UM-`jdSk3 zKkttoR5RYLnl)?ITUE23`OGE*G&r4-uvD<){W zB?yx1qpO*BVQJJ`-ynt0NT&>h@=w2O5V0J1_9zOnjR{&|=tOZ}_J1jg)~Ifs=K8U+ zj`Gr-54+eCb@K$Hh^)*#BPkYJR~9}+C0>45K#yF5K{uvR3^UGE#SL5+)eS(gz`?fV zs3t%Eb*i-z!?04Qz|$bxOh>01q4cYs1@}yqh3R+CA=w=uu}*g;{<&W9DoQW;;Q2B~ zUvg|}@N~Y_;!_?L#vmq_ZL{dQhpds!(c*4h(s4W>-jMuR!l-q)I>Wfwox_h2?H^(hp=)lRW69qOUvAaa;ChO9 zK5}v~_6{yPB*T!;v|wPz1WvORH1zQsfOoy^)R`oAQc?^8`9x6Wxixv&eu!1> z@56X9EK@#bV)hGe5Hy8rn^IBO1*U&1CFVt3y!Kq@{;AW`c3yjreGo`w;QO1c=Ys&n zY{vkZvhr~i{zc+KU4yDok1%ml?|d_JIKI|$Ks<)hrLvGUo1{x){YpFp;J_h)HCAz6 z?7~!U%A@l3semEB2v6lRqIRas9$`VNdxy5WUa5-~W4#;sm?$K}!ZeMa3C^T-71MC@ z9oCAy$gt-kT@_!22U64t*VB}%{IMc$(B9l?XN}DVw$(&wcG);o50*;pQswqvZlSRS z;pEyMvf6Mmgee$(7m?D?<^Za7e-08PKccg(ZEda#7bGCgdy-_^v5ihf-m!s*dSJ?b zk6QFKCZMd<_01DoLG)aG$-@b30}XT8?v#-1Z)5jC{5spS$Sf@qvX_f9#2qNw)^16b$;9NQI&AcKknfX&|{9>w0j2L6e zrRVqbPTxqizaJmaFh>t8Yc`ll3U&{7TIw`EP>Qi5r+)TSbmJ_~{}IWJ!esf`QC){b znBuHELtjWCghr z?XWr_F0e$~fWY^Ie(#8$7|swn-Rzal#vYIg-S8uD5aujMXiu8jBb*bYHkB_^Ke_s# zS!|&}wyx-SITlHSL>@uQHZ#-ly4A!}hX-F09~tsXz9fnk>`R^UaIWg+EZzIpuJ+3Ig}88XP!p|KuvDZ5)O+ zJyc~$75h@BWQI%hNqqoI=BDYjA2?D^>RHz%pO4?xqM2dg1br}G@z$#WenM@+)8fed zKxMv~I;Ek>Gb2ve(ZRftK)Hr!dqRd8*S&E3HY-4*$sc_+IiS+I)O1(TmtN1 zm@PAZ+i3Wdkun*5kW#vjUAfm0efKr-w#U+3AcL#E2nD;UzwhC;Ay;<1Jy6UlN|mo2 z4)E8BAK6n{j~BB~XHFQ1O2j4j4OpZpoNFqNRI)2nrtIYCX6ILm)Qbzji<^A1uU>%S zg7R1S{_;{rNmAQw`#MmNKR&!kAXmk+gx%G+T2a16)s9xX@k&o-HdDhKl@#Ctc~qX^ zy)MpWHZ&MsdL%O`P7lf&(_%6>Dy!$DJ(PqJK-baWztA7H2x{zEJ9z&l`b`Ve&> ztP}r^ax4GgTK?w;ZLIHjAinD$o)ODHCn(Q@?n2-U#mBgfd@f!JZt_kom$RLga5p$J zC2(?BA5=yn*9qcMSYz21X6LdzEnR(R(o1^MSHsS!_5GO}Yd^{Hed^~}_qQd}+ta|f zr%DBM7K>lC!Y?3#x9@LmTY8-jtb}*dybF76+`00m!9S2LXj+`_UBA_nLnTx@6L$Ty z&EW2i2e!Q8ysf8{Xz^sx{1RAp=&VShyKe_e9+|ewTfV^P#hIQ1j}hTvMN_t8XyZsN zDFvcNw24^D&eBV>mrRF_3_D|XyT!6K#h=2o2`H>8g5murn$ZzO{YsXFi)@xDGnxxX zTGnn1C+MqsQn$PNOV>|+aDGp7b%x`+KHzwEJr#kX3Vu@}+Kbgfn7)}ptzPq90npFc zWr4Pzrcd`FI)|>trRL?gDiS@$A(0=kgyKJSn1@NC>?SWf83o4*9QH}QlSDTRcufYW z;q9Sx4&BzEDXu>+!v#%RO6@1-P&4#KJJsgw&ER zSvAd~`X3%7-@td{s+(C+FDu1#J+w03`{}nt2Vg3P0bA_MazaO;6ct% zpr$D18LdjbZPC*1rMW|OV=C@VKV_`OJ6bIyuwoTN`Dhd*NmpChHb(~JBorEoMz4x| zezEnv;$T^$H3_j9WJTVag7IOjhad0z9*)$yq0D%K1IIDfDOW%Dd4R(86_0a8IdfxV zP<+j2H;WA?iSNE^ST&^oZ~N$m>AZBjS=s?W$Lc@hw9q9nYSs zGj6e534S6p$>ix z8pwychq3`@!1MUNgsevDxX}ry0d3xxFtFye2qqIrA zLfo3K>nyeGFGwth+?4wTJ@zRg>{at&3kBWgem`EzX1ZwPYvsVe5sO4#_GUhxjV7H) zrcQMlGth3Iswg?T!zfx|ppXC%)=owK3!ws7~nZc!1f75)OT0ffTQVjD*sKAn-NfoSH#DL8B#O z_8Tfi3!Tu5$mq|-`?^KN7p|}}s-ec~oy$Ieq$gQb6&-ET?I@E#ZtJrnt&f78lpO1 z>>@eKJOuZwmr5Iddh=PXsaye5MqW~B>EdCv%1xJOPrf56X;R|kamBItr;mpL8VvH3aMt2nRQ!vcaoq2H( z{`~6e*%@`Pd)v~;BI%Yt?{9!b=PAnL)(;iWT}H&BK%k>OD97~w1_H%O{@k|lcD!x> zg!T?!zcubRfcd%9{=LQ)Vq|tvBI>+lK}IcBrK;#n2fNz~WVc~0;*iU;qm<#5Ge(b7 z8NotYM#_lDc@|D~_<7Au3cXQO>X*}j?YC}ThsbH+>#2In3_#fAYO=m1;a!#S52LMU za(ZRczr1G+MI(C^D9k2LFgxlOKQ@6i>-Qrq{4}w3tQ$#S70OVt#rZs`U2j*i$*ed1 zorfb2Ezly;}chI+>nxlxeT@eF!z^Rg3@o@9Ko2*=u0z(PYo3N0*RK~H@*8tUVH)0(RqysZ`z;_c9jraZ2YHB5E&n$^;k zNoXIfJ}kKU2xg+#-23X*Xs_1^@1u>!#?DEbtLBcSkq#v#k$I)>g%@7HU;F73UX1scCbNT+GIDVw}+V|YtFYn+6{Fkc=bw2Z3C?fY2YAKm`W(M>(HB{hc zB@|y4RR#oaQN}fO`g6J3ykvhaR~NKK>M(hT8Jyvk$Fpv-8PX<^m@}tpZ|mg{ROY7>BHN$4}iWAY_gzH|s zs2S!-!Fz1PA9&~^aT-bS<9I(WkagTTG0_UxXOt2RK?h#T%yG z5gNB;n^5z-nuLLT7~`*>XN8cPqTi(nUGN0q^v?h!w`zG{5q8Ei4i%WgLw0~9kbK+% z0oHoW;qI+b5oI?Cp}W6$G8f}A8!(QEV4sd`K9Qp?692IZ%}HXCNjZqO+I zfh*S6MsJ{=&Nfij&Hc7i;8%nyOYhT9B>cX$YhrJuQGR6$Zn8~96!GQC)LDd+9!&VH zXY*SxeqU`GlgA5BqUC51R29JPD_`sjKNPvrC@Pgf+X~5B#GwEW_AiG35xS5)EjP23 z_UH{)LFdPaaxY0o(P#?479r#eJ&jG+~6m4&PzAl%%t)cR4^I(9@0K=m63 zP{i7+t_Gh@gI%T$ys)s&$~pyATr-sv`&v%2dE18!&cecGe}hg*uCf{;A(OYxVV8cs zBbbaLZluV($3&%itQ5E~V~BpJu47!?Jjv7?B+Ob1^I1?Bh9SbDWYFni-XXYLx{~!% zld^Mr?XB(-F~&QnzX7=s=xmhU%gf7N2iqqFgJmcr3+0PS3;r;bUWYzafHYG{5V(HD zmI{&5tW^Ma7aXcmm?nBPrpz;Qd{Bm$;bqJ8^u_d2n&re4SJ)w2MzM$*uy;#3G5Np>}5GbM}oJscMZ$i3FeVe?0e?u8RAb)y`Cx z7{5(f=e)lVzP&jmU|+KzAZbL7bc!I;>}1jL=K2_U60kRY%Pi{K8h*YRty-Tb3ujL8 zzLEySYbL$HYxVT){pWiOrew%*gpa#M^B7a;aM7@P>zwt`zAdRl{Xs;S3V#Kx4?SOGnAZSd*nspC zhEFzO_JDV2aSg8tu!IZtM3>@91z0Y0SmS7u9~)9XU~zkf39zt@d7bF0t)mUL^mTJs znxp+idW(*V>uO$p0o zd_0|t!T>%+!S-leLRx6=e3Fr!k%Nc>SJ?JVT%`oFBA<3G0@<8n8BiG5*yCt3I#@Bz}!YX?1g*=dF%Bz&iO z|ID|Q;tX=LW`3MI{~O?W*YW?0`2V>U$H!1UD^q9i&DSdzh(p7lR#BFuFm@ z;F-ZIx@;O7E~9Pk!~Nr@HI~ zP)t>XIhEu&or#m|3q&Kq=Qcr}kVBRj^NDQbJj49vk3;g7#K-I8)IW`{1x|UoH0W)> z5BCU$$*f?ZTtSNK(o~7&jbol195@x_P^OS2{kbR>G*DLfrkA9ONNOq^AHj%t<4Wi^bGIkm{#a5aW}V4>ULi zHNGZ~@bXP(sw^GfEhU29?zpg2Be)H_FRB3^LE;d?AsnvJT3mEt^x}qG`=7tu0u;3o zDeIu;f&FM9ycCVZr@b4&|*WA6`>RG`|lrhlk_}+fj*LPl`nrmie zZl-9DV_nCb=jHiI9*$A{7<=1T_Q%|ks)Vh2eFliUT)ipc(?ce=Cu84T-3Z*+?^|f& zR-coT+BZxZ481`Fb)S4hrloe+0}(W3ZN5o`xAArTrT4a6{sm_Cmrpv}(F_vhdSM?w z>x>p_%h0McybSU5VN6*>+{^wtTX<86Wzg6-^yh`z7OU3RZ?`$se*(V7xbHjE)ssJ410oVD`mhO z#^T@<{46A4BH4~~2iG2-LZde*RVrRz^;rlRlvST=tEbFY1pQH3Q2jbtaq^F0I|zwn zk-CmjE5Z{CB%C-!rrS5nkY!ShHu%Ia`Py_TW%I7s%KU|xms-3>PvEZb{!(LU(;yC1 zP)uw;h5km(Yx5P@#TM^SiR!(WC*#jDjwtStXO(SrO(WV>_@o9FzA!UU zWg5Loy0MH+t8MqTrfH59HQ+FQ{ak{8!p+G6R2U*?L?5k%Pj4+B_tNxLUNJc~W|goY zP-C12CiB9mtNi$i!T+&)y5#C6_IS$lKMyqzT@Rq9l{JI&Vy8?xJsF? zvQ8*KWee*yJAVxmq~^!rbUJ@XnOt9;GWTLjv2qZlFV6XUN)6DOvA+OJCy z^-;^gC^bfOiGBeW=>m)ObnyY`8SIx~ClR@_rB%!m^fp?fN&QymOlgyB`Tl1DZq8GC zZ|8RnE)9@Yn0asyC@lBk!0E?KnT)N{1sN{rQ0*!AtfgCY12#SZ&iYcLshPb(Q-NA_ z|CX7taZ5izpnLE>YLWbCcu$8SC{NJ+4XEgcoV|GMs%*!mURN|I!EkZCq#DYgh2coN znWPtmCV{m@XFHeH$dWhLcA*4&gSshFYqv$0Q10PzTI=N6_q>(KG^nSALEJ93)*N2PrF> z^hTyiN(YBwiM#V9*Y2G9McD~7s^JSN;hhM8?K&QNRS$~XY-$K!!d&Joe?m%Uo$y|y zd|N5%3~D?mA57`0Y||PiO`p%(O2k;CwqBv_Q>O87z8^pNI@UTGsH7rmoygcVf>*)w zp?v{@S7B4dI`2HhQEFdym|t5T*(;!?HF?31Qy$TEj0(EF&TZDH+lI zFj<#(MqW=jhgmdcz(95fB&_cSx@%Vf3%wGpnhwklH4;h5m#Bt9PG2{D2YNMr>ZyBz znH2600hxQKsOz0s!g zrLg;1!cc5i@J3uvNpxNY0P6D0Fh9EGWjvs^{=wRVd{?cjb$dp@26$KJm&#;qwouM1 zASc5Mp0p0l!Es*0SnMI0{aZmin%{uuxv3jld`D%@9w_o^?lnFQa>~(Ia9mv9dUhdj zciLOu+rU-U?4f4CTa0&2(b&`)uMw~{N+X-Gvtbp5uq{2Ir}jZ!72H`B{?B}k3>=P?ToQQ~MN?slOQ39my829=Po-0S^2qb%Ed!NMV}JzOOyh2uf!R%7`P{67nC+2lrHlL zd(r@XaClRjoU-yPuvp$hT^R;Bh;#UH!-SLaegw-eA=1KDq*Q%X-QLodWJslm{|9+I zDzc|lFYJyZ{}{FV_0+&#Xi84Wst?^bd&Q4Q8;44cO|rBGQVl)i+OXS-`p8(J>9D|% zRN&y||3vRbg5vsqv79bUJdQ4AC`mU;HA6P2%lZbdX`PIr7Ina*;()1^#-**M$i3WC zXKCyfKoZPSebpZvezuW<*^CyV*K6{Ev;FZLUN-^Pf_s?6a&_@8!afBcWfUR|O#ALLJ5lMvw> zuU$karX)NVDxGBHRr9-QWXt%p=ObmHa!`m^O)UTKmm??%6W z(m(w65k!ywN|wW&#p~d4t@~~i0#1?0(vVXlky_75LlZavQyi+R8Vw;T1WS&Jd0>j^4JfqZ=|=bpL1iN`hreQ zF5C~NLkkc3qhXW(yqzUvJ5QsXXgy*7K zp&8^xoyp^GqA&v_--d4;b=I}nN9hW9AvZhusAn9R-9*Rtw7x&HO%j}a4NTw4a zg6Q$1@IOWt$dJu}KO%<>OjXTo@M{6Z{{XYjO}p_fw)cjvVmj`+u34V6Mq>e29# zsZP~dTM%ESO;;&>Nsh1W{W=w^03wPYR15SNG%;N&Q@q7&m{NNpR_qG|onA;o3 z`u@E@=6q_!?QJj0q=Ho%lN$HP4XZLf0goLD_1l2tC!3EE1CS3*R9&mr{UDP4h<+^tQxY|q97CWP$Tp{1%tnxMatCl7E-5tB7 zjuNwdTP^=*8tF!sikid*Xu9q*0QT1Gg1wh>iHPl)3*S@mCUJzA_fv4%=~O8-$N)ej z3RuMbkCO6fVoP0YNE04ajpROredb!&3}Yo8`HQ|G|I|FO*)-9HM&*DQ z{P?9Ky*mGfDbVhPvO6vBw{IIB3J3Fg1}L99|1L$9S~ZheRjD%pv!={`+BQ`2FY^6a z)c*35@cX*zb5q-2l#Nc8VPzHZYrZbrxq23s{!0Y9?|oUbMRw;(7P?DK?4Qhhv*o(@ zT%Tc(ZaA<3AS`N!yQifN-7g>@+gnmMXKeo}J-<;?hi3Uxvq%Gqtwt??S)?apndQ;v9 zqL8$0vN3-alO-AZ0^!e({;)J^hH0(wBO3iG`|Kpv5W7!%8J7Gjk*CqF5Il8-39Z)X z5vIz=-5}@hCAhjlZmKWM%9I5&|LnZhUyAThSPh}gm!-?h)qDAyZ|VyBs#Vqgm`{yK zAM(bz_4SHrj2`w%Tx&xMa#AUGi!Gn^yRyW;Vc%>wVPBU(W4izQdQS*#zaV|@X*cW* zjhBsQO=lPEmjYV)qe6+;tN4Z72!;DNMZJs8K@tXf2xp!=*xcK9pH4|P&B9w60jP{2 zkblhrsehG3ev;IFIH>xzbb2e*H-wlFpw6|ncG~ZUs4_GTR{_l;? z>R(3n?9b9&0mJ2}+2C_ng;e`aHj10%R?enaF^_$IR(_+?vAXC7^39;Ph^2D30Sp%2 zV=hVk!04?B**)T2ba-brdr8AJkzw1PZ#ddNi&CJl6ViX!Eld6QIjAYcnf3EK)TM~i z9=~$`k#Q`rdCr7{q98>e!qKopu%*jxg|A;OR))MEuJt!Hs$|fM?dTMKfq~$t?H*$w zC`wzICtcu(bJ(F)f3Lcj!H-AYSYCR#xsewO+ixBU!=^)>x zTDd1q|BD^`S=905<64$sHQD{QoUHI=_g@~#AjX;Ye7VxRKH9kt8I{EFJHj^>+s zYvYq|gs6EuB5%J9ElvX|8_g^e0=cqT*+fhWV0GrQZ8JPl+vAX%3%eW4?b~Y&)G9KJ z%FOjCLF*n_ad+c#&mQwjS&;T{4&~gf{S8&`0RZH*xv;oIj1AwEMRa##11MhgP zbE&NLnvTDzJDEnlREk%!!n|k5QS{JrSE^U1<8LTQ-E^I!8!4_ z3sC`&MpNQ}tPrwxM+*1+n$S@)^40;mb@Z4o?{eezCtz;I!NZ@tMZ0TAT>Ih|iJV01 zuJZ^2cc>mKU`nY?T8y88`YpevtGI7;eU)mEmGnjHdHLid(jpopN%_s^?55P0b4q!W z%`&Y4i<8FZDB}y-w9ng9Em6n1$NNF*a(D9SiQT)J1bj^(D!y$zLh@@p+DGzg7X9l||+ zUZwH-Nfdi~Ua6mkt%$pq=a5^55y2MuUiDNb^}EX~@A*B`MGvt|75s~M7@Oa^)Xdjz z@*qB}5Q}eP5Wunv_ehC;y)>$_jBvrw;?JQYx8mOn+tZMN=L_v^tHvl-k8&N&0lk`T z)Q49;yqDGG87Pbgj0E`Wse-gb;`s$RV>>pxt{blK zc4lWiR&wOqNoO95q+P^;N@A5=;i+a;yVOhV*`76D_^NIVb8L5!z)NK(wqQMLdm$$* z`F{B7^<*j(@rgpBHm-01HkUUH7VK2eB((uxVy6K_;5tTA$~MpA#rpF;gx)QbG$m>T zbQWXJ=Uauw2nt2N)AcPD{0+dUF6juYloK32nzvy3l=zmPz0Pwxdl%SP=9f59EOilB z7SVo!v}~jg1rPw%Yr&~qjTs}$Dlr;CZyOhdGn5~EK}V-l@ICbH%~y9800DQ7)>~uq z9GO*Jn66T=gSjptRMXGCl;t~BI7yY#y!(=-3xy#IP|N{urh%??b&u`GX7v-32|uDNO!cTyD`WqS9Np1W#fZa3_n(A^#+00_mz$9az5Z1 zkptJgfhbtZNkOA9vHz^-P+#4^bF{Wu7jImddz|oVQf=s#_Kk>#CCczh#uuen zeuz8K%;d4MJCe9NIH|&x(>Sv77Xar!ft>$Gf1#O=AbkoN*K3fkWe&5))3={cN!7|( zufhk~j%Sw>QEnog^A{B;duH@RMVDt@rB>+k{PmjwZ7>yTS&QJ&N3BU(vHvqp9c}bi z?!75w1#-jXj#$EVoHiO?ZJbzZ@;xLG;IEt|bU<|(0OV^L%EK`Y&M3X9+L`owOw(IdUH@Jl%AM=AE4 zxXwAE@J7}~o@{ngiMrJ!6JQtV1XCNuj9O1gefB8$iPgY)Vw?mE{T8-Xr-nZA%0U!A z1JKtF7uUp=lD7vXB~LZx^<1|biI*8!8ve+liHOFb7KT!?R%QMWE#XebTabCCHqEIj z#`l%r#g9lT3(q5Is!ig_U+$Xzi?UM#s*l)!ubK)|RhgJAWs)ps#8*5e`ig2wBhod@ zGam7%PRy7NnQHr6dw$>#s0a9YUXNnGl=qP2&Jbz~pW@oNqpfkOG^Si;0)R>{ukqJ&-3{9XO|+@@#3>k(ga$=P-mBiY$i zeWRN9+4GzYq&P##HK;qvKk5@1@9a~Le8Yo_VCJi82GLKl(FLq8pFr8CT;rqa1fiy= z5IfMq)=qh{{0q3_L~A<6#ncM-43aoQzxQDpZL!q4$=Qi-bw5jYj6ccDN4y3JzyVvK z(TFq2%yR?xVm6?qC`ZmH$=a3>%gBZe;+wdVta@i=U|I7zlR-dKP4 zRdJ_#|LQGkaS!%jFR^5P&Z3dMra~=ex0F9vSX#+a^3V^7Ug3Dh&KMq{<)WI>OHNAG zV7K9Zre!Msr8=G8RKbaT%I^4;GIi=|=-!a@s^T7mqVYVPDZSi2v>Zj<(t@(_shTIV zI|&Y0Z21|=T~ERu^GcI~9cgfPL<*KmOzrjO!lmPstnFByye}C7&<90-`UoG7ukbaV zb7T%{Mmq6;u2MYoh6T4tLDaBjok5Qh`?r|H2ELbhh4io-_p6}o=Zi&ox?deQ-+~G(}pvx;dF(P z(LJoMCB!(RngTstMAVM?WNc4S&tbf?{Y3&M3H>?Q09-~6*se+Cnr|4KR&iKwBPH&5!z6S;`&5|W)7D1QMU3-rJGktgudM0Tm)<6 zEE$YB#Gx@JuGn7puo$d-cCk<-7j=H@cO6G)kUzH~`l!BE#d8s++Ee~$7Hu~bG2bt2 zQ1izEa$1iSsn|vpDhJ+3myCN_wNsBs;l;=YiNFYjJRi9@hWP5P$F^WgxViEj8M7}p zUPMuFDjo)u#ih&J?Q3==|M2(Jt80jQ8>M^PuqW}oJyJg^J-BIS-|it~F}i{09e%*Gp|CN&36pQ@cUdo@>*0Rh7lFa3Y^|?Q;JQyJM3YqY z8P7Ey>pceRFa1ozn9Kz*#M%YHEN3 z>+qNo25)qI811+|r1u6+M7JUm{!f}A<#xKT6ZQVQov{dGZRIW;A*dbu{t))n8ozG% zL#A0l(d?C%pGGK@IfICMW?j7;C$?-by={q%d>tnCSKZUjUX$Ko5}|ysM7M0$UGMH! z?)xg1q<%f61c3?CSN-dhHJ2R-H!$_Da)VtB(`a5&;iGuFpau4}T6JIN&0ZxJwKF$I zGoI=mdsWie-es!Yu`mDaFle2JUZFr?apujCVTjsCFnX6jb z`Jxd?$|;DxJwyy=8swNhHSNNH;&lpfjXx7w4~6Ty=7!aJYQODh_S$N3bue{)_2=3e znWy|`?uc(cMef+Q|5kE+-Mci3Wz~BYfqFlfP|F4qQq%bLBDNRo5vMBJUJ}`qSzgVQ!Uj{kdh&{&JMYhyhIJIIu zszpnmn%(xXhOIA}2}gCxr?(_Wv9En3dQEiwHjWqe4PF3a$Epdxa-%;6u>KU0iZc6) z1{D9j1N2OVBl8e?Ir=X4w39UR;b*H8Oc_hh%MNqg6n3BF8_uy{w`wqs#`sOdQ*y}} zr23Y>Np#AIGV$$@M9`T~y|CKs+qgG%ApEPXLu_}<&z@=A;%FQfWi}sqUy{Q=SL%3Q z#NCX^>E4)B-xcg4`&|W01Mge&%c+mqxW}MmFmeHO)eH#|77UEQV>k`5e?#7V6 z8AjuhFuBA)g|WV$?3oN-0?*VE6!T|hWc(SF1zzSjg?0>SMd#A}Oc;4SD#Kjc>Z$Cq zB9x;LJHo7OZGIR$;-*N}OKkpkCeD!=FLAjnmvW49a7Q=owGs5-?(YJpj6ISX(?~TP zNVdjbKDvnGFDEU=RPJK}M|$V}ZB2gFIwq*=0q_`*p=(6E1Z*zAp^Q~*<7*4re6@DG zARXO-o(rzAeXod3UNU{-c=pXnSe+{VDoVVAj8|4#vw@1}z599TzsPMbW@`xTRzT->~uk7NoI*GkBkadv4WM443~nkiN! z6yW_58(jpQd@JuS_5ClFQ4+6{c!=CFRr^e&t=!PFROFRu!;)Fj>BWP*?~xh?HIWCKTxtBM zStk@%?@|+%=-Q&h{#u4H(yHZeb@kr}J)F1v!udW#<1?7+RHWxlP~QKp)=#}QjU`(7 zT~CHZBpE#&n@KcoyT~;{jMApjmlXLNf1oMnDRp)qvPqm)ZL09!r^jEWqkd&-q==69 znNYNRXw*w$;l=Yt#-tZEITGmyJJ#_Yc5BM$U*BW9ySl!J<;!qzk{nQ%(hE5-pT7%X z=}%L`+SoI2_O?EokFHt%o4Ha})?nOvvt#kgn`mGiPVJ2d#G=ZlFtD3;AYnEb_0!)> zN@p%F#GIrEZm5as49HU}4c?Q{cEhEzqTcy?l~3hO<_=U`QtI_pz6cLbGZ@Ajmnkta zGn%{75^jF^nDM*x&Vm#9%9D;B2iX0*1k3zuB1NWFD-B)+{Kv7+xD_#0sO}tk|5huy z@(NrI2e6qDDhV@wvs*_PY--Cis%lX@;^Iq)jp-OJ!RUt9Vg_LWNYhGf{2m@SHqf)l zq-yg;vb|y9H9wXN`m?{hF8*yQiAD?3K<7tGX0aH`U};W!ZT!87^gmfI+U6~8Xw$c@ z?tMl^n!L8Xyl(4zVeXgOih>&_KQc@-82MQ*WyJAj{$3}~g(tkHYdhrVDwG!o#DE@h zSSi9uxCa$0CkoT2sWy>a8m0rUWoTxH)v1S5eqvq}k&AydDhMX~4JdneTTew(=v~Y9 z_q8X#olk&(c|KP@bs7LqtB-v;9631bPKj1#WlBZVHc@zm4?pa2cFynQV3(Yko}^l5 zy1Yjk{(XH@dAq}GP4lC3v8Th(aFu$2&h-*yG3%8I00Dz;u(G|8T% zqb?%(lB1f(0U21h0N&Df5$#u@iz5>LxcYv&E5L7iVZ8U}WU_acT7)R_E*Lsu~~K=i6#(AiAZ+Rtr~Y09gBPs|I>( zU}a{#oQ^#Iq}8ZNk4?DcvIzPlKxD$H+`S* zAtBiKp5iwkHZt?P>o4^$~*F5mQ!NAN&RkA^hUk%q6#sDr5KtttMCnsXgV57<)=4OO(qGP{dbn z|6q1PLw(S5<(P`zuT%r1C}!?^>+WycP`5pJ{iy4in0l#w6f>FVZt;iAI}}*{3c`2) z3}S_Xngp5;L4xhHq{)8+W>B#F<>XV^RmBSw?0)mM_m_U~GqnHa`D4gGer?qkB4Uc$ zug@r@vd59yfNHIwZ9f+xDy>mCn?JAI@)ZO9@a8w*y5#bo_3Dc90Aqd;oC2^ zXwLh;K3`%!!(8U@v-a&pg?3ADl;r*A z@&11$Kvnsh8;Qa0G^9AiE+}&nvcbr+dK*mlv}e}298c_Vwkmk42J)}&mDtn%{Iz^O zgqpKJkH0bd|N9YXiehI&Zg_Yv`e@dy$%JDFP{yQmp#Q=oQ&~x5L=z3l4xFYPx$t3TX zQc>=Z$(gWnM=>7&{@%$v^s@txG)Vy`G&jl86;K|(-)`Je+d>lybrL{2bDK`7F@X=~ zlsU2Gb~tiUooLmJn%&=8y)aX(9UrY^;V9_)k|D}t<|Ec*10wCM9=a6es3{-jj&j-J zvsAqu@;%=`KhMIa_Lr|ezK61;yED0|Qk0T}#y3Y^KBxv&{7OOHkasWNxySqlNE7#I zqM0Dzw*kW_-#6vewCZ2Jj6b-Km|DL_M{(^}d6?DF9@Fj{Pqyn(enneYgWbxn4j$p} zJ+$|)tjqG*jEpZATi@}AgqES+Xj6qZKU&<)4aN1=oHTyaxs|=-ZFb+C#zdRHso_`L zlOcEXf9i)OP2&k#E#0qpv;@kvG@9o%PfP1l1|YAkA+aD8cn6^%EY}P~5s-*Dvs6{J zH%WF~_NbNIk!Za3Tx%4A8qZz+Fk_uK8zohlu&fP21^PjjsK=>1IThTOKTf7@-ty#j zawFaKy&{w^ApbXj?tirR9Z*fRUAl>(hzbaT(m_E*DJo5RQ$R$D zsPupoX)z$Z2?3Sf1O%i=M>>dx-lc@zAxMan0HH_;%>W_J@t^tpoVnjWYt8)kt~+bi zpS8})KIJ|2efQq)v)ev`eo+9l^Y6G8UF-;1b_N(RFjAp?&~Nl(7!lE0mBv?FUHQ?r zZLryT63@P=*estDgAVK2da_-gE=0m&B;Ybtt{rkNP)C2^i^xQ?nt*Oix)|AzR-yr% zhwN6fX!}*4BzQ_~aqY_d3EVyHsl2K&{uGH--s>ON$bXLG`)Gb) zW)sEfT#e(6(Zg@@#n_^aioL(aJHejjxu{&>`M|+1*@25eRTn(>6+_2*`gy(WlAXLK zycT5`r7r7}JY={t&2FciV}QZhmAs!6+xs9Gw%MtA({YBgEftbBfA9i~e*@q+7WO|t z1Y*-}FGBRb-SieiFoCR^I|i^R0%G+o**a^aX`YuJM~dW;2HZ&BvY(S@YpmQHOKaGY zd)LFfPt$9~NVQQ)uQ12Ixe61oxKbiDyY3G|zKs?r`P~7<-^YZl@ zqhX+}A`SNNHDv*ID-mtM7h?CP@cTZ%O)`2q<6GGx-1Q&a66iYqR_r#8B4&zy9c?(v z3DJG2+JxRYyd|G`1Lgy+p-zmw)w9jeIZuy@V9UcDvFm)Q7+lY*x^hYy-jEvEp!LPy zLLYSCv8>1;2W0o;$X_-#QXl~_cdiPZdi=kw=t7i>m&dgW?DfWPh!iI>7T@g~JS(|a zq}LRPn1}yl?pxQ6PCYo*SdoogGAf?*oeL1O2{Nl)@xHz%ZjYcfGxoIL^oEDRWxtx( zs()>zUPS$@5HJQE8)ZX8?8+%)9@H4aO4zn6w&9>2YmRxFF>jlU0cTAe0$s&X-R8mE z0`KWbR8a`r`~;I4<7bIdYCQ2khe~Qw=9VM;;$mISmxeYP>2{|Z`X^c=B7D_mP1;8< zd|kJtDDUNsd9BXc-AE@wpIJ)YHrY%M74Olo+X>&YxwDqA@P1;@9hy%=Vf8X@#Zyio z94*!{RMFEXm5zuxuQUDCG~?(Qpbm`tmHz;70f-lrdP_Xh@Bl^fzI^1$-8o2gWf}U& zIWO1kAxN(yX0~X}QFGK$a8F_4k>Om|)C_+8VCD*LtJr&8mbGBY_UjqK*=&2YcN7T` z;HB1Ho|oU0cnKMF(*6Cu%6sfG2EB2;vkYp^hykOj(xs6lw)#nUTTGXrlDh3Savn0h z3a!BJsRb3|30ko$)?+%QDRk{WKq{Ay>~^|$Se8?rX`v03$hf)wJYVnP&E*6OVpc=~ ze`pl$y~{2W7=N%BC?6o+&@eh!(Hlc!6(ph_EXQ2k;Tycm91mS+86v@LO3Yf##e<4q zXG~ey7Tz1a@ttv&#Q9UnxU-bf`Jcc8K10WQh=}u0N|%FZ(yJ#Vh1VH0uF*u2GPGVTvK_QnKX8w}eppI??XZXIehnhDaT%w5F22IZjhe)j9sTSd~WtTu#j> z@7}C1(C<3&GVFH+*=)#r3ek)xf$3@eAqwA~$b&(aT#VS(%Oo0#r|exiV!9---AT=# z12=YxSNI`!QHIH_YNI=&Q4-NQ456%_;wRKuNULtLo~rS7d72r^E||#-gK>i{R+JDh ze$~H=civY#yDQK(Do*2&jeId=#u7w18SYOFnPw%~=Q8O~YW}Gy8y_T+UM`Rn-WEfK zUvpl}BY6R@$OOIraE$g(dbD|X*ewYe*u8s61AV2)v&R+8-dIMg`@l zYs!)?|N9Z4*h#@F=f{+|ughn=c8Y%bsDNaZ)xF4h^Y+Nj@;dH@iT1JBc5NO1P5%Rz zeScU&mjBP_fE(fnBFXGvQ6VWGxv_t|l?Z4Qx-0*uV0g_5WNf`hD}c3zt#RKQF%>h| zA@D>dO2NO;3@oT;+Hc!R_ci8G*zvtypDat|C@`Hi>d*3LPI39fg%{5R#u6ZG%(pFX zA9CinhkjBJdH+niN&MZv8WWtebK$nYC4rdaT_7$Vh(`PO>vw2Re9ALzOep}yPvL;$ z)$T$p&4V=i3Z~}rd{g<%0;p+cVVRR?cXtEWLLIVQbj$FqryWvTSm9!6u;k@E#{r@nj|x?}|JFF6fOEPchO$YOoJ#X*`7HBqX!vI1MJDJ=!$jA&v^Cqz(7 z`)&}>qkdPW2aAs^$#Q4Nwe<705T>2d!kP!ewS^#oy90*F1Gh(!$S8?0QU|o(L%3t= z2GCK#P>wXQQSGpc=^-m>?j(nQ)J zs`-}KEgaG1i*Hk=)S@l$jsA=5M##)4#Xy5HnSapGD7WzGKyT4tx_4iezZjC!8V)fC z)_oy4AIsA$nAFl8gIU%7gtjRkEZeER5UH|#?VW_N*Q2FuAit-BGwf;@2$=7Jf_@*# z0y(w7#6k)XbSa3di>SMbS8F22(1ov6VTNwi5|Kl9*{ea^tA@aY619h|B5kK^apTl} zQ3gBz_3bs|Gc6dVoIMKg5$wuT=eM1`UNfc-gGgxX@m3=@U*C@t|-1jUFj;*TnEx$jc$j*&%pWg0w>_kNVNm>3w+a)v| zt_kknS8uAE0g>I}R6vkiX!)q_utd~ti<1tN_VG;M@}nyF50LC4DVR9)Cpj+n5APY1 zSyOR5hGG-RkO_6j8I$G*$q7Jzb|u2kuEaoEy$}YPAY%YjCC$a}7T~1&i-d9gxA#>2 z+u2}O?ULs_lKd&7l_rx^Kn9;`&&KUX_F#H{q}8PRFcumejTbTFctMYApr+_f-V0=v{3NqNZRN_GkPz z-`(R5qvEM8LC;>HZ$gF8ByUYXTw(V0#qS(z5H*f&`FbW=y}WTVrl}!OD`;-cJiq7M z2FvMI+s+kHRN38a=?w?@OPBK8KiYpiGq}NPWiT)QfaVT_TkutEscvfq zjbg(>BnDiOm+J>E41*a)<%ZA)hyISGJKbsf9a010xi+|PdPZW94AkYbx9kVADM4q= z6Cx&8tRWsrv08FeqHBs=E-G-(x?9?`#4?>>%Qryg>X$w4vhj~uU80CQ+}`aObVajY z!)?kuyT?a#UujyD_wX%26Bmv=P$chxw>Qhb@Wn5JwV&cjt~3siZ4dG%^uynH_AA+ zSW!Rn`ZM#JQb^wUfC0X=qz-y9aNrE*WsSx-hFI4ccQTn>6}tPlj>W#Jw9R%X$7Tb*%@ zHF1G23d{<)SuPWIHdS(n8=t)w=9Vgrv`TUmh4qY2TZUQfhd$uuc_xkL!+qfK_i6y< zN9^+F2KfkFNFXoM3oKKg+cW%03W1&)1+BDs8%`K(PAewIj;%jg%=l&nvUbFxb_@F@ zMQ{M^Bs)U~Mlp{=iI8?Svlp|2J5aGcr+j$2UiJ2zsoGS4bMvfs+*BGJ4YS%DK6qEs z_|E8j1;)nleTxlWng!|Oi}_N~I27Q6p~&jAY|6G-7QB-(aC$Bvm(8v8 zKN|1e>h<>bT#@Y1x*0)|ahyHU8lBJ-Jb)h+dnCl(y^djVbpUnleN(X|-PWU-y?NC= zoo*83)WYkIcuQK@XuI@i6A@r;acVX1ocXlnaR71TRpj!~6MVWj>UI();6^LgR&?rd z>aku$?t;SI3IHW;qRIB87d$GDmBm(g!jy4Si; zvQcXAu~zNO9@w0nt4vCYkC$bQM4#+8-HYeTt5dD6J;!C1)J^0nuvkYb8M2$oxS$M) z3i&z2OhH}JopB?^6QK-R3iZ4?)A?fH>^V)y=RH%9#u1%inS=S5${Y076Fsx3M0jW_ zW&ia%1JtonvXt)W+W-u>4usoa?B|w1rFkulT;*d?xdp2tJzUYbikGTSzvj}DqG7|o zpQD$bz)5jbxHq!sA%fDRPUJ=jYJmohSzq4Cpq{pqrVf$4h$!>){_HD(yXV=Cjq4rZ zRh{==X|s`9od6*?Sp=U8Wj_}i6342wA|^dNK4~xouMM|;hc+t+tEoUT^5wZcw$IXY z^jtZ{kVhe<(D7L@y#!W4jyK=5Y`s=woBb%X)P{z&)>DF8M9aCs?+y4RBG=Q*WYapg zY{?z%{p4%%V0ieIi`!XGVk%!0dks7XQuRc*B+m+r)~}kKBgu}N4+?SL3cvfs#mOR8 zFa~;wWg*?xxz$dRFFM|5tI=4I(zTIxlO)}rDgHHcYnjbCw2W>ow?*>K8^X5Kz8Y_n zRQuyElYk$N@fYJuhvA`m{E0jc){>CR0bON}$Ldec8Ee3KTPKB6pA5qlboO(o;eECvRqJg1QBcjac9Ikl)SzcH8z#{&UCrm{S?s(m`E7GkSs$iai|?n}pzV`)4+W0zB3Owriv-~S zxrBzNdj)ViZ@xF?${mL{UUX-q(NiRYHa*Q_=R9Wu+0?BbhlGh3hBhB-I5P*7_XLz6D)2~X&P!Hp^dxggI9fK7372e`7- ztIZvoIv&kM-*YmsT$Dw-FrZ0ESXf#xYZS{F1$QzeE-~Rs6 zZ7pnx%x!m9mVHiBv&?n%O4)-$;Ypvv=&LuX9p0Q-d04>d^mJ|dK1uZ=Z&r}-17vT<=G#%{PM?$y^-{_R zti49PNJsAwxs&gA1&HxTnZ-UcRr1@g7c5;bv0}Wvg(4Yuh!_Jd&(8;`lmDo~^%wu( z%p3#?gFuUt+TnV_F@Tu_Q146zwwWvL9czple|{}{wHtvH%=U5$5Fve}qmwu9>hR`> zw%_k)5YYNSOm_@mssfu8nM|o%QrO74lR>qLpmF5E3P-wDsgEj2(OhN4MPR?9I z9`=dMW2TLI9QpB2^B=~fT6srFhwWjdF{sU1hm9S>(Oo-U=N=;eeIuiij(2vs@dVBO zcY>Oodcn393blc6V?{B^iqAIy*&M4)ukM>pkHNOn`8i5$c*M#S4HO1oVOjUtf_bAmOwWx7Cmi0}6w{ej_P}&W+)bjEvoLqIN z#sdm%C!I~+m(LQ41ncgZEjxlkBEPigxTHqO1=`!2iXzD^>8hK1fn1R=_m(pDHCov? z_+e3v|L0xYbfuOT+uu?pgUL_Rw*i*0k!{>4NRT3^jJ=wEBJp{+TSl|d;pp%rCzeXI zF0aZ6zm!4uxwXUF$M!7XI`&+?w$1%wW7lO27j>k;e8E+^*=AG*bIcrqL3_^k@z)*- zy+IUP3mks>vl1iTp5DZYd>II_?f_=3uFkT$f-!Y`A-4pswCG9$Sz(Ym)EPfOpHU-L zqn6|A&o9CiLKvv78LhQhE7m>gH9)a&9zIiQ;kbw${f>^qPIX$Pd9fLC_}>)eh(p!n z+h)*~tpRvP7Gjp;@FuCv54#sFN>2LrrHVVsg{UV47-fwc&k+P0*&5&VeZ+pjHjjUI zk6O?(z~px>`O?Xx8+`^Q+kM6zXLX6*&@)Pd7DH>oPZ+W3NU;t1DJEzy_{8ykIbW&1 zx@#PEye$VnjTOYHcd7#CJk%)incl1z^Q4=?d>?We2A0jt5WTrX|CP4veh%NgQLA7$*bRW6OS9ax09Lssh(Yz zb_Y-&2%=4%4~ozldK}wsUNZt$$)2JS#b3bLu;4hpOHFy}Q8MXJE6tjn;XVm~>8($P zp;LwpNXAfQFUs<5oLv_M9j>XwYB_Ps&buTn^Ej2UVXPJHVEki6`Kd=n{19XvVO}eZ zUqV{_Q=-|GhW7rAi)sfg->KH-8@;%FFsav0t`2)zwz+$^>4YX@qb!7w((zYSeV%EH z$Ebj`eZ+2_`!0&Xgxm7Pr%6H_wnk%>@r~51`2f%)O{>w?arjwUEjY8%mgj>PUra=1 z{XWb54R+NV36Qv!y_`YP9kIwWCd2Q`jq7}MDQ_i7yv@;Lwz;oC@lAD2Z(4X;q zOMF3lVN%Ar0y!c$J}DWIxuy2?d7!BQ^_Kh+bHUfX+AM#asaNhUPXAI z*N8ov#Au-GIsJWJ&L@r9;UzC8EU3CVZQVU>(e6^xz8#-M@3gKxFvkVLUyccs5qDDl z2AA5`8vjYZK4Zjw-#Lh24fFE|F%U?TY~hKjUNcIw2}0n}`hZ(&2rvl3@MJW=uoV~( z(-zSc0PxXf_I)CQ?q%=h0ODuN#7N955(`lp=l|cnGZ`kyL(we8WIXvIBtW zd!V!oaC~I|KszR{G{BUf4mATDNO^(aRDtwA50?LRo4}_NZB^J_Eds)eZX-x4T>pHa ze}18VcDa9!q5suP;R!b7f$L(QwXvTB&0EnOJRe9JU-95C`6E!af>9vL>TyOUC~jTA za!v0CX#4B6!*BXm_Uat>iQ(i!Cf`yF+3x}n$I7p!Wjry5)dL^aeFx?Rvd}=lsqvV?>af`nXpp*p=P$8cJ!Fp(qVUU? zgsZ}r?}XD~-qNosvL{~-%&Hjy5iSfYuYZdd>HxadXCpd|=BclML#t4^!D&7yLzR0sGKT8`1BJKn8MCJEW|{ zvZiW;rIlwYFy}U(_iTvx0D1)U^Ct~B3$X)!Xov0GJ12jDxh>sY38at;!&2+2+`miaQ3zzHWy-(e0lu6C=rROD(D_eZK z0lrKY7(=d!;5DP1F6I!#RHamB0)lAFv=`PCS$=xf{70~z*+#ogf-Sye2HNq}>W#3| zyBrR`c%v}T4qSQ1)3Sr$8O73jpq0n9Mu^Jv$D)ZJA&+sT0=3#_J$={w2F1g#r+Ap> zf(hj1{ZDHV=-0MsR}=4j@|E5j7E-(CtX}yRXSe&HUkXo>9>clKoK02VqkW=Zf48e@ zTPS_pUxE)vTJmZddurR%W6Oxio-0V;(QS?=-^2GieR2O zFZJVDgrb19KEZKP441RCr~ZC9hqM%#n0T~Esy@X_ z5+5@rSc2ZNqhp~-4*&Iny7Ouo1NNYU6ZN0wMhY57PG6tmbyoEP#YE2|t}ZmqiV(Pu rDAyHk80sgYjRIS$>w)b0(UkK~Q@wrpkNrfQf3Fw%KbhwK@#S9tEOD$% literal 0 HcmV?d00001 diff --git a/src/client/bluetooth_impl.ts b/src/client/bluetooth_impl.ts index fbc7c2f..194f1e7 100644 --- a/src/client/bluetooth_impl.ts +++ b/src/client/bluetooth_impl.ts @@ -27,7 +27,11 @@ class BleConfiguration { ]; } -/** Uses Web Bluetooth API */ +/** + * Uses [Web Bluetooth API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API) + * + * @category Client + */ export class NiimbotBluetoothClient extends NiimbotAbstractClient { private gattServer?: BluetoothRemoteGATTServer = undefined; private channel?: BluetoothRemoteGATTCharacteristic = undefined; diff --git a/src/client/index.ts b/src/client/index.ts index dde9d55..3315675 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -14,6 +14,8 @@ import { findPrintTask, PrintTaskName } from "../print_tasks"; /** * Represents the connection result information. + * + * @category Client */ export type ConnectionInfo = { deviceName?: string; @@ -22,6 +24,8 @@ export type ConnectionInfo = { /** * Interface representing printer information. + * + * @category Client */ export interface PrinterInfo { connectResult?: ConnectResult; @@ -40,6 +44,8 @@ export interface PrinterInfo { /** * Abstract class representing a client with common functionality for interacting with a printer. * Hardware interface must be defined after extending this class. + * + * @category Client */ export abstract class NiimbotAbstractClient extends EventEmitter { public readonly abstraction: Abstraction; diff --git a/src/client/serial_impl.ts b/src/client/serial_impl.ts index e315372..0fdd5ea 100644 --- a/src/client/serial_impl.ts +++ b/src/client/serial_impl.ts @@ -11,7 +11,11 @@ import { NiimbotPacket } from "../packets/packet"; import { ConnectResult, PrinterErrorCode, PrintError, ResponseCommandId } from "../packets"; import { Utils, Validators } from "../utils"; -/** Uses Web Serial API */ +/** + * Uses [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API) + * + * @category Client + **/ export class NiimbotSerialClient extends NiimbotAbstractClient { private port?: SerialPort = undefined; private writer?: WritableStreamDefaultWriter = undefined; diff --git a/src/events.ts b/src/events.ts index 700e24a..758bb18 100644 --- a/src/events.ts +++ b/src/events.ts @@ -1,6 +1,9 @@ import { ConnectionInfo, PrinterInfo, NiimbotAbstractClient, AbstractPrintTask, HeartbeatData, NiimbotPacket } from "."; -/** Base client event */ +/** + * Base client event + * @category Events + */ export class NiimbotEvent { readonly type: string; @@ -9,7 +12,10 @@ export class NiimbotEvent { } } -/** Fired when client connected to printer and fetched it's information. */ +/** + * Fired when client connected to printer and fetched it's information. + * @category Events + */ export class ConnectEvent extends NiimbotEvent { info: ConnectionInfo; constructor(info: ConnectionInfo) { @@ -18,14 +24,20 @@ export class ConnectEvent extends NiimbotEvent { } } -/** Fired when client disconnected from printer. */ +/** + * Fired when client disconnected from printer. + * @category Events + */ export class DisconnectEvent extends NiimbotEvent { constructor() { super("disconnect"); } } -/** Fired when packet received, converted to object and validated (head, tail, checksum). */ +/** + * Fired when packet received, converted to object and validated (head, tail, checksum). + * @category Events + */ export class PacketReceivedEvent extends NiimbotEvent { packet: NiimbotPacket; constructor(packet: NiimbotPacket) { @@ -34,7 +46,10 @@ export class PacketReceivedEvent extends NiimbotEvent { } } -/** Fired when packet object sent. */ +/** + * Fired when packet object sent. + * @category Events + */ export class PacketSentEvent extends NiimbotEvent { packet: NiimbotPacket; constructor(packet: NiimbotPacket) { @@ -43,7 +58,10 @@ export class PacketSentEvent extends NiimbotEvent { } } -/** Fired when raw packet sent to printer. */ +/** + * Fired when raw packet sent to printer. + * @category Events + */ export class RawPacketSentEvent extends NiimbotEvent { data: Uint8Array; constructor(data: Uint8Array) { @@ -52,7 +70,10 @@ export class RawPacketSentEvent extends NiimbotEvent { } } -/** Fired when raw packet received from printer. */ +/** + * Fired when raw packet received from printer. + * @category Events + */ export class RawPacketReceivedEvent extends NiimbotEvent { data: Uint8Array; constructor(data: Uint8Array) { @@ -61,7 +82,10 @@ export class RawPacketReceivedEvent extends NiimbotEvent { } } -/** Fired when heartbeat packet received and parsed. */ +/** + * Fired when heartbeat packet received and parsed. + * @category Events + */ export class HeartbeatEvent extends NiimbotEvent { data: HeartbeatData; constructor(data: HeartbeatData) { @@ -70,7 +94,10 @@ export class HeartbeatEvent extends NiimbotEvent { } } -/** Fired when no response received after heartbeat packet sent. */ +/** + * Fired when no response received after heartbeat packet sent. + * @category Events + */ export class HeartbeatFailedEvent extends NiimbotEvent { failedAttempts: number; constructor(failedAttempts: number) { @@ -79,7 +106,10 @@ export class HeartbeatFailedEvent extends NiimbotEvent { } } -/** Fired when info fetched from printer (after {@link NiimbotAbstractClient.fetchPrinterInfo} finished). */ +/** + * Fired when info fetched from printer (after {@link NiimbotAbstractClient.fetchPrinterInfo} finished). + * @category Events + */ export class PrinterInfoFetchedEvent extends NiimbotEvent { info: PrinterInfo; constructor(info: PrinterInfo) { @@ -88,7 +118,10 @@ export class PrinterInfoFetchedEvent extends NiimbotEvent { } } -/** Fired progress received (during {@link AbstractPrintTask.waitForFinished}). */ +/** + * Fired progress received (during {@link AbstractPrintTask.waitForFinished}). + * @category Events + */ export class PrintProgressEvent extends NiimbotEvent { /** 0 – n */ page: number; @@ -108,6 +141,10 @@ export class PrintProgressEvent extends NiimbotEvent { } } +/** + * Event list for {@link NiimbotAbstractClient}. + * @category Events + */ export type ClientEventMap = { connect: (event: ConnectEvent) => void; disconnect: (event: DisconnectEvent) => void; diff --git a/src/image_encoder.ts b/src/image_encoder.ts index 8a3c661..8ed641a 100644 --- a/src/image_encoder.ts +++ b/src/image_encoder.ts @@ -1,5 +1,6 @@ import { Utils } from "."; +/** @category Image encoder */ export type ImageRow = { dataType: "void" | "pixels"; rowNumber: number; @@ -8,14 +9,20 @@ export type ImageRow = { rowData?: Uint8Array; }; +/** @category Image encoder */ export type EncodedImage = { cols: number; rows: number; rowsData: ImageRow[]; }; +/** @category Image encoder */ export type PrintDirection = "left" | "top"; +/** + * @category Helpers + * @category Image encoder + */ export class ImageEncoder { /** printDirection = "left" rotates image for 90 degrees clockwise */ public static encodeCanvas(canvas: HTMLCanvasElement, printDirection: PrintDirection = "left"): EncodedImage { diff --git a/src/index.ts b/src/index.ts index 619dcf1..44fb540 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,7 @@ +/** + * @module API + */ + export * from "./client"; export * from "./packets"; export * from "./events"; diff --git a/src/packets/abstraction.ts b/src/packets/abstraction.ts index e7a249e..e30638b 100644 --- a/src/packets/abstraction.ts +++ b/src/packets/abstraction.ts @@ -18,6 +18,9 @@ import { SequentialDataReader } from "./data_reader"; import { NiimbotPacket } from "./packet"; import { PacketGenerator } from "./packet_generator"; +/** + * @category Packets + */ export class PrintError extends Error { public readonly reasonId: number; @@ -27,6 +30,9 @@ export class PrintError extends Error { } } +/** + * @category Packets + */ export interface PrintStatus { /** 0 – n */ page: number; @@ -35,7 +41,9 @@ export interface PrintStatus { /** 0 – 100 */ pageFeedProgress: number; } - +/** + * @category Packets + */ export interface RfidInfo { tagPresent: boolean; uuid: string; @@ -46,7 +54,9 @@ export interface RfidInfo { consumablesType: LabelType; } -/** closingState inverted on some printers */ +/** + * @category Packets + **/ export interface HeartbeatData { paperState: number; rfidReadState: number; @@ -54,18 +64,28 @@ export interface HeartbeatData { powerLevel: BatteryChargeLevel; } +/** + * @category Packets + */ export interface SoundSettings { category: SoundSettingsType; item: SoundSettingsItemType; value: boolean; } +/** + * @category Packets + */ export interface PrinterStatusData { supportColor: number; protocolVersion: number; } -/** Not sure for name. */ +/** + * Packet sender and parser. + * + * @category Packets + */ export class Abstraction { private readonly DEFAULT_PACKET_TIMEOUT: number = 1_000; private client: NiimbotAbstractClient; diff --git a/src/packets/commands.ts b/src/packets/commands.ts index a9f2f52..ba9628f 100644 --- a/src/packets/commands.ts +++ b/src/packets/commands.ts @@ -1,4 +1,8 @@ -/** Commands IDs from client to printer */ +/** + * Commands IDs from client to printer + * + * @category Packets + **/ export enum RequestCommandId { Invalid = -1, /** Entire packet should be prefixed with 0x03 */ @@ -39,7 +43,11 @@ export enum RequestCommandId { PrintTestPage = 0x5a, } -/** Commands IDs from printer to client */ +/** + * Commands IDs from printer to client + * + * @category Packets + **/ export enum ResponseCommandId { Invalid = -1, In_NotSupported = 0x00, @@ -95,7 +103,11 @@ export enum ResponseCommandId { import TX = RequestCommandId; import RX = ResponseCommandId; -/** Map request id to response id. null meant no response expected (one way). */ +/** + * Map request id to response id. null meant no response expected (one way). + * + * @category Packets + **/ export const commandsMap: Record = { [TX.Invalid]: null, [TX.PrintBitmapRow]: null, diff --git a/src/packets/data_reader.ts b/src/packets/data_reader.ts index c3b0bde..9f8cf81 100644 --- a/src/packets/data_reader.ts +++ b/src/packets/data_reader.ts @@ -1,6 +1,10 @@ import { Utils } from "../utils"; -/** Utility class to sequentially fetch data from byte array. EOF checks included. */ +/** + * Utility class to sequentially fetch data from byte array. EOF checks included. + * + * @category Packets + **/ export class SequentialDataReader { private bytes: Uint8Array; private offset: number; diff --git a/src/packets/packet.ts b/src/packets/packet.ts index 2081ca6..b8daf50 100644 --- a/src/packets/packet.ts +++ b/src/packets/packet.ts @@ -1,6 +1,11 @@ import { Validators } from "../utils"; import { RequestCommandId, ResponseCommandId } from "."; +/** + * NIIMBOT packet object + * + * @category Packets + */ export class NiimbotPacket { public static readonly HEAD = new Uint8Array([0x55, 0x55]); public static readonly TAIL = new Uint8Array([0xaa, 0xaa]); diff --git a/src/packets/packet_generator.ts b/src/packets/packet_generator.ts index 31364a3..e1b6a3c 100644 --- a/src/packets/packet_generator.ts +++ b/src/packets/packet_generator.ts @@ -14,6 +14,7 @@ import { Utils } from "../utils"; /** * A helper class that generates various types of packets. + * @category Packets */ export class PacketGenerator { /** diff --git a/src/packets/payloads.ts b/src/packets/payloads.ts index d75f9a0..90f09dd 100644 --- a/src/packets/payloads.ts +++ b/src/packets/payloads.ts @@ -1,7 +1,10 @@ import { modelsLibrary } from "../printer_models"; import { RequestCommandId, ResponseCommandId } from "./commands"; -/** Sent with {@link RequestCommandId.PrinterInfo} */ +/** + * Sent with {@link RequestCommandId.PrinterInfo} + * @category Packets + **/ export enum PrinterInfoType { Density = 1, Speed = 2, @@ -19,17 +22,23 @@ export enum PrinterInfoType { Area = 15, } +/** @category Packets */ export enum SoundSettingsType { SetSound = 0x01, GetSoundState = 0x02, } +/** @category Packets */ export enum SoundSettingsItemType { BluetoothConnectionSound = 0x01, PowerSound = 0x02, } -/** Sent with {@link RequestCommandId.SetLabelType}. */ +/** + * Sent with {@link RequestCommandId.SetLabelType}. + * + * @category Packets + **/ export enum LabelType { Invalid = 0, /** Default for most of label printers */ @@ -43,6 +52,7 @@ export enum LabelType { HeatShrinkTube = 11, } +/** @category Packets */ export enum HeartbeatType { Advanced1 = 1, Basic = 2, @@ -50,6 +60,7 @@ export enum HeartbeatType { Advanced2 = 4, } +/** @category Packets */ export enum AutoShutdownTime { /** Usually 15 minutes. */ ShutdownTime1 = 1, @@ -61,7 +72,10 @@ export enum AutoShutdownTime { ShutdownTime4 = 4, } -/** Battery charge level */ +/** + * Battery charge level + * @category Packets + **/ export enum BatteryChargeLevel { Charge0 = 0, Charge25 = 1, @@ -70,7 +84,10 @@ export enum BatteryChargeLevel { Charge100 = 4, } -/** {@link ResponseCommandId.In_Connect} status codes. */ +/** + * {@link ResponseCommandId.In_Connect} status codes. + * @category Packets + **/ export enum ConnectResult { Disconnect = 0, Connected = 1, @@ -79,9 +96,13 @@ export enum ConnectResult { FirmwareErrors = 90, } -/** {@link ResponseCommandId.In_PrintError} status codes. */ +/** + * {@link ResponseCommandId.In_PrintError} status codes. + * @category Packets + **/ export enum PrinterErrorCode { CoverOpen = 0x01, + /** No paper */ LackPaper = 0x02, LowBattery = 0x03, BatteryException = 0x04, diff --git a/src/print_tasks/AbstractPrintTask.ts b/src/print_tasks/AbstractPrintTask.ts index 0f53ce8..f78909b 100644 --- a/src/print_tasks/AbstractPrintTask.ts +++ b/src/print_tasks/AbstractPrintTask.ts @@ -2,7 +2,10 @@ import { EncodedImage } from "../image_encoder"; import { LabelType } from "../packets"; import { Abstraction } from "../packets/abstraction"; -/** Print options for print tasks. */ +/** + * Print options for print tasks. + * @category Print tasks + */ export type PrintOptions = { /** Printer label type */ labelType: LabelType; @@ -54,6 +57,8 @@ const printOptionsDefaults: PrintOptions = { * await client.abstraction.printEnd(); * } * ``` + * + * @category Print tasks **/ export abstract class AbstractPrintTask { protected abstraction: Abstraction; diff --git a/src/print_tasks/B1PrintTask.ts b/src/print_tasks/B1PrintTask.ts index c885303..626b14b 100644 --- a/src/print_tasks/B1PrintTask.ts +++ b/src/print_tasks/B1PrintTask.ts @@ -2,6 +2,9 @@ import { EncodedImage } from "../image_encoder"; import { PacketGenerator } from "../packets"; import { AbstractPrintTask } from "./AbstractPrintTask"; +/** + * @category Print tasks + */ export class B1PrintTask extends AbstractPrintTask { override printInit(): Promise { return this.abstraction.sendAll([ diff --git a/src/print_tasks/B21V1PrintTask.ts b/src/print_tasks/B21V1PrintTask.ts index b6323b9..4076a32 100644 --- a/src/print_tasks/B21V1PrintTask.ts +++ b/src/print_tasks/B21V1PrintTask.ts @@ -2,6 +2,9 @@ import { EncodedImage } from "../image_encoder"; import { PacketGenerator } from "../packets"; import { AbstractPrintTask } from "./AbstractPrintTask"; +/** + * @category Print tasks + */ export class B21V1PrintTask extends AbstractPrintTask { override printInit(): Promise { return this.abstraction.sendAll([ diff --git a/src/print_tasks/D110PrintTask.ts b/src/print_tasks/D110PrintTask.ts index e782096..03c9080 100644 --- a/src/print_tasks/D110PrintTask.ts +++ b/src/print_tasks/D110PrintTask.ts @@ -2,6 +2,9 @@ import { EncodedImage } from "../image_encoder"; import { PacketGenerator } from "../packets"; import { AbstractPrintTask } from "./AbstractPrintTask"; +/** + * @category Print tasks + */ export class D110PrintTask extends AbstractPrintTask { override printInit(): Promise { return this.abstraction.sendAll([ diff --git a/src/print_tasks/OldD11PrintTask.ts b/src/print_tasks/OldD11PrintTask.ts index 1102416..7a21e83 100644 --- a/src/print_tasks/OldD11PrintTask.ts +++ b/src/print_tasks/OldD11PrintTask.ts @@ -2,6 +2,9 @@ import { EncodedImage } from "../image_encoder"; import { PacketGenerator } from "../packets"; import { AbstractPrintTask } from "./AbstractPrintTask"; +/** + * @category Print tasks + */ export class OldD11PrintTask extends AbstractPrintTask { override printInit(): Promise { return this.abstraction.sendAll([ diff --git a/src/print_tasks/V5PrintTask.ts b/src/print_tasks/V5PrintTask.ts index de2e612..8affe0c 100644 --- a/src/print_tasks/V5PrintTask.ts +++ b/src/print_tasks/V5PrintTask.ts @@ -2,6 +2,9 @@ import { EncodedImage } from "../image_encoder"; import { PacketGenerator } from "../packets"; import { AbstractPrintTask } from "./AbstractPrintTask"; +/** + * @category Print tasks + */ export class V5PrintTask extends AbstractPrintTask { override printInit(): Promise { return this.abstraction.sendAll([ diff --git a/src/print_tasks/index.ts b/src/print_tasks/index.ts index cf6cad9..581116b 100644 --- a/src/print_tasks/index.ts +++ b/src/print_tasks/index.ts @@ -5,7 +5,10 @@ import { D110PrintTask } from "./D110PrintTask"; import { OldD11PrintTask } from "./OldD11PrintTask"; import { V5PrintTask } from "./V5PrintTask"; -/** Define available print tasks. */ +/** + * Define available print tasks. + * @category Print tasks + */ export const printTasks = { D11_V1: OldD11PrintTask, D110: D110PrintTask, @@ -14,12 +17,19 @@ export const printTasks = { V5: V5PrintTask, }; -/** Available print task name type. */ +/** + * Available print task name type. + * @category Print tasks + */ export type PrintTaskName = keyof typeof printTasks; -/** List of available print task names. */ +/** + * List of available print task names. + * @category Print tasks + */ export const printTaskNames = Object.keys(printTasks) as PrintTaskName[]; +/** @category Printer model library */ export type ModelWithProtocol = { /** Model */ m: M; @@ -31,7 +41,8 @@ export type ModelWithProtocol = { * Define print tasks for models. * Model or model with protocol version can be specified. * Model with protocol version has priority over just model. - **/ + * @category Print tasks + */ export const modelPrintTasks: Partial> = { D11_V1: [M.D11, M.D11S], B21_V1: [M.B21, M.B21_L2B, M.B21_C2B], @@ -39,7 +50,10 @@ export const modelPrintTasks: Partial { const tasks = Object.keys(modelPrintTasks) as PrintTaskName[]; diff --git a/src/printer_models.ts b/src/printer_models.ts index baa1387..42e6245 100644 --- a/src/printer_models.ts +++ b/src/printer_models.ts @@ -4,6 +4,7 @@ import { PrintDirection } from "./image_encoder"; import { LabelType as LT } from "./packets"; +/** @category Printer model library */ export enum PrinterModel { UNKNOWN = "UNKNOWN", A20 = "A20", @@ -69,6 +70,7 @@ export enum PrinterModel { Z401 = "Z401", }; +/** @category Printer model library */ export interface PrinterModelMeta { model: PrinterModel; id: [number, ...number[]]; @@ -81,6 +83,7 @@ export interface PrinterModelMeta { densityDefault: number; } +/** @category Printer model library */ export const modelsLibrary: PrinterModelMeta[] = [ { model: PrinterModel.A20, @@ -722,10 +725,12 @@ export const modelsLibrary: PrinterModelMeta[] = [ }, ]; +/** @category Printer model library */ export const getPrinterMetaById = (id: number): PrinterModelMeta | undefined => { return modelsLibrary.find((o) => o.id.includes(id)); }; +/** @category Printer model library */ export const getPrinterMetaByModel = (model: PrinterModel): PrinterModelMeta | undefined => { return modelsLibrary.find((o) => o.model === model); }; diff --git a/src/utils.ts b/src/utils.ts index e7ec81d..5b4962c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,6 @@ /** * Utility class for various common operations. + * @category Helpers */ export class Utils { /** @@ -149,6 +150,7 @@ export class Utils { /** * Utility class for validating objects. + * @category Helpers */ export class Validators { /** diff --git a/typedoc.json b/typedoc.json index 8102976..1005dd4 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,13 +1,12 @@ { "$schema": "https://typedoc.org/schema.json", "name": "NiimBlueLib Docs", - "entryPoints": ["./src"], + "entryPoints": ["./src/index.ts"], "navigationLinks": { "GitHub": "https://github.com/MultiMote/niimbluelib" }, "treatValidationWarningsAsErrors": true, "excludeReferences": true, - "entryPointStrategy": "expand", "out": "./docs/html", "projectDocuments": ["docs/documents/*.md"], } diff --git a/utils/gen-printer-models.js b/utils/gen-printer-models.js index 3a9a981..977f763 100644 --- a/utils/gen-printer-models.js +++ b/utils/gen-printer-models.js @@ -33,6 +33,7 @@ fetch("https://oss-print.niimbot.com/public_resources/static_resources/devices.j console.log('import { PrintDirection } from "./image_encoder";'); console.log('import { LabelType as LT } from "./packets";\n'); + console.log("/** @category Printer model library */"); console.log("export enum PrinterModel {"); console.log(' UNKNOWN = "UNKNOWN",'); for (const item of items) { @@ -43,6 +44,7 @@ fetch("https://oss-print.niimbot.com/public_resources/static_resources/devices.j console.log("};"); console.log(` +/** @category Printer model library */ export interface PrinterModelMeta { model: PrinterModel; id: [number, ...number[]]; @@ -56,6 +58,7 @@ export interface PrinterModelMeta { } `); + console.log("/** @category Printer model library */"); console.log("export const modelsLibrary: PrinterModelMeta[] = ["); for (const item of items) { if (item.codes.length === 0) { @@ -83,10 +86,12 @@ export interface PrinterModelMeta { console.log("];"); console.log(` +/** @category Printer model library */ export const getPrinterMetaById = (id: number): PrinterModelMeta | undefined => { return modelsLibrary.find((o) => o.id.includes(id)); }; +/** @category Printer model library */ export const getPrinterMetaByModel = (model: PrinterModel): PrinterModelMeta | undefined => { return modelsLibrary.find((o) => o.model === model); };`);