From 531e33715f36af653c9c32be09bf8fa41d0bf2e3 Mon Sep 17 00:00:00 2001 From: Anton Weber <anton@antweb.me> Date: Wed, 7 Aug 2019 22:54:11 +0200 Subject: [PATCH] docs(ble): Add file transfer documentation --- Documentation/bluetooth/file-transfer.rst | 189 +++++++++++++++++++ Documentation/index.rst | 6 + Documentation/static/ble-low-effort-flow.dia | Bin 0 -> 2331 bytes Documentation/static/ble-low-effort-flow.png | Bin 0 -> 13295 bytes 4 files changed, 195 insertions(+) create mode 100644 Documentation/bluetooth/file-transfer.rst create mode 100644 Documentation/static/ble-low-effort-flow.dia create mode 100644 Documentation/static/ble-low-effort-flow.png diff --git a/Documentation/bluetooth/file-transfer.rst b/Documentation/bluetooth/file-transfer.rst new file mode 100644 index 00000000..c098c6cd --- /dev/null +++ b/Documentation/bluetooth/file-transfer.rst @@ -0,0 +1,189 @@ +Bluetooth File Transfer +======================= + +.. warning:: + The file transfer specification is still work in progress + +File transfer to the card10 is implemented using the custom Low Effort File +Transfer Protocol. + +BLE Service +----------- +The service consists of two GATT characteristics that act as a bidrectional +link, similar to many BLE UART implementations. The two channels are seen from +the Central perspective and hence named Central TX and Central RX. + +The current draft uses following service specification: + +- Service + + UUID: 00422342-2342-2342-2342-234223422342 + +- Central TX characteristic: + + UUID: 01422342-2342-2342-2342-234223422342 + write + +- Central RX characteristic: + + UUID 02422342-2342-2342-2342-234223422342 + read, notify + +Low Effort File Transfer Protocol +--------------------------------- +(Version 1) + +This protocol was designed to strike a balance between ease of implementation +and reasonable levels of functionality. + +Features: + +- File push from Central (e.g. Android) to Peripheral (card10) +- Path and file name support +- Chunked data transfer for variable MTUs +- CRC32 error-detection +- Basic error handling + +All communication between Central and Peripheral is packet based. The first +byte specifies the packet type using a char followed by an optional CRC and/or +payload, depending on the packet type. + +START: + +===== ==== + 0 1-N +----- ---- + s path +===== ==== + +START_ACK: + +===== === + 0 1-4 +----- --- + S CRC +===== === + +CHUNK: + +===== ====== ======= + 0 1-4 4-N +----- ------ ------- + c offset payload +===== ====== ======= + +CHUNK_ACK: + +===== === + 0 1-4 +----- --- + C CRC +===== === + +FINISH: + +=== === + 0 +--- --- + f +=== === + +FINISH_ACK: + +=== === + 0 +--- --- + F +=== === + +ERROR: + +=== === + 0 +--- --- + e +=== === + + +ERROR_ACK: + +=== === + 0 +--- --- + E +=== === + +Flow +---- + +The file transfer process can be described as a series of states from the view +of the Central role: + + +.. image:: ../static/ble-low-effort-flow.png + + +``IDLE`` state: + + - Send ``START`` to initiate transfer + +``START_SENT`` state: + + - Wait for ``START_ACK`` + +``SEND_READY`` state: + + - Send first ``CHUNK`` + +``CHUNK_SENT`` state: + + - Wait for ``CHUNK_ACK`` + +``SEND_READY`` state: + + - Repeat previous two steps until all data is sent + - If the last chunk was sent, send ``FINISH`` + +``FINISH_SENT`` state: + + - Wait for ``FINISH_ACK`` + +After ``FINISH_ACK`` was received, the transfer is complete and the process can +return to ``IDLE``. + +Error Handling +-------------- +Three types of errors are currently supported: + +- CRC errors: + + If an ``ACK`` packet contains a CRC that fails the verification, then the + original packet must be retransmitted. If three consecutive attempts to + send a packet fail, then the transfer is aborted. + + +- ACK timeouts: + + If the Central does not receive a required ``ACK`` within 10 seconds, then + the original packet must be retransmitted. If three consecutive attempts to + send a packet fail, then the transfer is aborted. + + +- Unexpected response: + + All steps in the flow described above have exactly one expected response. + If any other packet is received, then the transfer is aborted. + +Aborting Transfer +----------------- +To abort the transfer, the Central role sends an ``ERROR`` packet and returns +to ``IDLE`` after receiving the ``ERROR_ACK``. +If the Peripheral role aborts the transfer, i.e. the Central receives an +``ERROR`` at any point, then it responds with ``ERROR_ACK`` and returns to +``IDLE`` + +.. warning:: + As this is a custom file transfer protocol developed under less than ideal + circumstances, it does not provide any guarantees, especially not regarding + reliability or security. The protocol assumes a secure link and a + trustworthy peer, amongst many other things. Use with caution. diff --git a/Documentation/index.rst b/Documentation/index.rst index 50fdc4af..a5be0e5c 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -48,6 +48,12 @@ Last but not least, if you want to start hacking the lower-level firmware, the epicardium/api epicardium-guide +.. toctree:: + :maxdepth: 1 + :caption: Bluetooth + + bluetooth/file-transfer + Indices and tables ================== diff --git a/Documentation/static/ble-low-effort-flow.dia b/Documentation/static/ble-low-effort-flow.dia new file mode 100644 index 0000000000000000000000000000000000000000..7dfc86360869474e57806bf5da189e728d210876 GIT binary patch literal 2331 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 R{_5&~hU5KFi^Q857yxlRiv|Dy literal 0 HcmV?d00001 diff --git a/Documentation/static/ble-low-effort-flow.png b/Documentation/static/ble-low-effort-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..da33b299973316817a8e16574564d50dd9af7aaa GIT binary patch literal 13295 zcmeAS@N?(olHy`uVBq!ia0y~yU|h_=z<7v*iGhLPY`kF%0|NtFlDE4H!+#K5uy^@n z1_lKNPZ!6KiaBrZ*2f5^H`#xX<ls__m@0ov<+rI2Z^u@qugAOc4koP)4O}xP?rA8e zc3?nYxNG>S)z@~fUH0qHtIE81i93r{&v<jSb@!{Q)t!%+Ze72+Y15)LrPT?nQ-ejO zvL00U`Oolq$t?NFE%7I9YVOsy&P<<InKq}U#^~f{o?NrpnhXq!DtGQ?WMHWEd-9I0 z;rXJ>TS=UDj13MKca$BRReG%O;Vj03j+Yu$|IJ8#c#4tnV6D{;PW9w-OD8epwJ&Lw z-zgQxVJ*O=BKt@Fh?oG6C%bJ^4U410B}Rsy6G|KcU(8~BIiZBX!A?b%VFJG=JHr#_ zON_3G2bd@DK{$^63ye9M8kRKwZ$87+r1<iI`?@ySLxL?#p6vDyYbq3<IXD>D%id_1 zY0+rlVYPvK^J->8uz`1$GqY#RI`*SpzzW%HkhN&m(N$<##;kW!jTq)RgF;h1sp(9P z+3jdn1)VKtS4*;4ytXi&efCc4jvR-G4=+XMG_8~2kebAo^Wgoah0g3v%}baWJ}JID zU{)<_Uh=}B1ME)~*&C^MYn|KqShye|#wees&L?Xnpa=CfpFyl;$qR=I22wpNEIbJZ zN;zt|Jk=9eSmv0<Ot>IEp~T7cMn&}@K6V@4Nq!S<#3;O(-+$#X({|@eoc!mX6s9Qr zV_5kA;qLH8Ne;~eGO`oP6%WQjY@R!Tr-e_J`L5NASPv@(1^G#Q3@6&5ZghSaCi_K6 zW$y2XXL&AMpHTAdxQ&-+CHsZ)2_<q%{(sif)6-K|Z?8RT;-Dk8`fAqNu<Fmxd}pif z<bFASSK(u~|6An_WO`WjANbojNBVd9&6_vXCciw`%<i`MVv3Qgt847Onwj;Jb)&a! zDQIbJ{pugg7^75F&V0aZ`yY=P%Q7c=s0ei~TC|9Zi%UvMYSX4odNDf=Z0_vu?{`sp zxt@)wMEF<9yhCX#c7FdCTU7MvXt%hp+T`6*3>Tu=N-kZLYui8fZ)KVUSL>q9n?Jw2 zyxb=B+q=8cUnT{ue6xNT;|{j@ajc8~A6~a`p`(frucT4S@}98OXHT6<imR^VeevJo z;AF*@HW>$O{HN`Fn!ZKdZ_W(E<hK5Pe*c*b4GgVL7xR6YUdXA;UA|#@(qG9VX`6R$ z-u(IJ=jZ16_iPFtIJmm9et+E|t{=B$`}WQCzkdCS(w8yG5U479&{z;yrMLO!o%4Us z&b2Q8_2UN%8=IP{>P3^<r>CZB1~1!?U1~K~{`lkL{cFYN+1Ky0m*#n}gwb}l)my{M zdm~F;yfHmlEOp18?bb)9`v;eYpKmHRb%=Mkv{SxHkD->=^LgC~i-vt|`6>sT7p~^s z%K=SJu<SAS!;aJ~_4d*n$2tCTdaA21zy0>d!8-1RwTD%sB!~Z*L)+I~cnwNTSvMwD z#XN}n@pQw74R@^${j$qBCRpt9z;Z%~(@`7iiAw8)TV^!xYgi&|aOmAl#m5WYE4*Y` zFVEDpq5q@-!$WCK)Re@~P=lVha0$K0H#Ifo<m7a8bWGZ4VPjMC`r6vJZ{KdwO+MC> zXm;|{sYRK;R<Gap=$f#&_;C?#4vraCrCFYyorkLu4me$M-2dv;t69eBeLiZd*R9LT z$}*DRS-5cFzJ2?2_0P^S&Az*<^vvtk;p>A$QjKQz$yf?WNUXU2S~u(TxpQVSeZGGE z`tjq(&d$!<++3Tl2OQd#G}o1We|PuSuV1{<W<4^NK{{gYZf@(MwstMjIO%=w-aR`z zyEEAvBYXlw0s{lHvscHh|NrT<zO=OT&aD?sbcH(G_+)q0{rz?A+O=7;q~=v6C^%no z+&}4LO4e2@Tid%CCinK$-k$0ErK&b4C@3juQH-9xhQ@}-V+jTwE{iT)xNt8=TY$xr z{qL#Mr&sUUW22^)_Wj*mt*KdWZfs<0Zd_gy8+&(W@$;bI;LKTmo}MSqpMUPhu`B<+ z-O3QHi5^8oMLlkdebiq6R%UQ?y5v~T&B=LlYj${QYHD$Dv74J)QBhH8>DIl6s`kdM z3^{h}Sdhrliy2wj+1}pXH@8Nu-L`7gsx@nLl#~{&S+mAIivLi{66Wm_JyfL4^S*rj zy7hanV|seJqvOH3*5ysj&CN|sYX0+l0!6-8bJo|_uMClrm5q&v_;E9Re(b)Qo%3h$ zIW<4`aM+)flXK?m+1PD4Go#kNd-3AL>C?tDeSBIXtxI2B`TP6({-4igPnaN(c5<e1 z`n7ejzdt-YeBgjXp667rsk3Iynmf1l+nbwq_G|(QUtTVV?>zcQ-G81=>@E`vi-@H` zbM0z(?bs2qHte>}n(ME{_2Xn@W!F}CF22|!Vfg69#l_cJi;Id*oj$D}v*W^cc7{VP z{7=~J9!?DRJJiXv(0M+h;KP+RiA&TQj+}A3{@I9O9`oka&Ac|j`AUx+IxZ|{_RcwQ z(d6t|(|7Y{)JwFmdb0B^5N2m_xYWq|C)TXwg+l?PK$g9cw*GM&pDc$Uv?$)aW_SLJ z3yltnFTw75aQN+!h0g4UTA_tB<1+1bK3NW_V|%%pZ?kLd*v@z&@`a+x+~vj9$10iT zNwPD{X<YI-=1!0FgZ!drAqwvo+%A}Z&bct1_h9wxYM~1!Tk{+)RVw-Pr3fG5+r{ho zyilOnMxgA1t%ntV>x|9p>1?|gJ)cKj2rXn2F0%-KV52fu-Dx}Pf^w*PumsA(l`B_z zdU$YfaS3%FefaQU^!B{m{QTv)lE!H~n?1wA#C$Ku*M1e<K5xeki)9fG4hOER4EFZ& zlDYPHgQ}S6=Da&Q4(jbMc_|d#9HOPGr&m_GpJAQTB~G94@auCdi&KmuOG`_GgC`$M z;Na!``t@sWW#+Xtk*}|<O^%D-TQzl&#^jSFPfkocaKK@2Tz+75S=qLeDXZ46@9*#T z_wmWe&VIb|_{?b=vbX2lymUxVOzfBrKM&8HJ(ZhXL;t*Ge_^RI_rRUK)!X;&t2^Ar ztL)w<(tUK|#EGlJ)-KZU`ZQ_#_U--s{GX$A#DYaaLqe|Hy0z;1>-~Q|oj!KVEic!^ zx7%gWLg)5%@%#5}-MV$zvbN=N>d}W1wx@2`|H;?ed-dwo)|H=@xaOXFFTOx}LJ5=d z<davjN~@}NUCh{1`+J-5>=$2uEm^YU$Pt&FF>wI_37dNkCJ1!8-0_Qy-_o*3qtj(m z?eA~7x3|soQG5QK^@6j9RpZA`pS1M#`#U>t?ycVLwN%QwY|X)h2b%HW;pOk{?7VU% zWY)6aprB8mKksBV`1ba;`cyAfAx}TQzKa=CPNwX=I%#k9cecGtLbP^DFI&2_vby^D z)2EjE^&8}zE^+#Mc$`=lyIV_Jd-m+v#zsbyCQn|ydi7h;Yp=h0Ej2PTo3==!*DW|Y zIyx%q)Vix#TSG%bQ&Up~1qD-6Q}^BwT9(H4U7Mq8k&DtqzvZ_#CLh1N+&}iNvcq?U zmn=R?6LaqDxOn~g^?P%FpF4N1sj11j{2dEBJ3A|@?>w8Ci!|PS7y9?_U(iYuE2~`_ zHhkE8-fnlz&!YUTDhdh?A19TD7d|}H`uJGy<(DOQZ_75UHrT!EfQgyevuDrrqPO|1 z4J$7xdGhq>OdmD1Lu=+*mA?A-_xJsp&%PcW9Gjn<nQ5GTeO>L34~Yp03fq@>E%oyC zJ$vq)UG=w|^;@1C?G}Ig_HE8X$7Z(5%D+$cU$w3Nw&&-w*?#Z17qnkkE-bMz;?I+l zlb3o=XJcny9kS~3a({7g@zqzeX19K=`upf;_u|EiZ@!!Awph|I>Bz;!?rXW9KY21` z`t<l61q;KY7F~Y%$Ku?4`}~bRudEDyes=ctYuBE=naKQw!FGZ=$EO488!8ee+X(xK z>|m({HOSswZcOIo<uy(_vms)}%$YkgFRN|e!hRt1$Cp=;^BZh7c+TTg=Zb0aUyr3l zJdf4isFZDAA451av-UUV$=a8^042S79lX|0WW}qU1d1PMsmyIpx_^elnyp$+p!fo> z1n;w*XVQ#6e{;LBQJ@%96!f=Mm+7R)d|{d7$8hJL+VQ)F0#<jHgPXDp#8>X1vf^AS zxfOiQrbtWIKym%JIp+EIK0G}9_wQeIpBW1-zr1zp){MW;o;)!~m9wo95f(PC{`O}7 z|G)3|mNhZh@J~8t8XFs1{OruclPOoPUiJ0$WouS6F}ZU6`u3+wBR8k5jo#i@S^M=> zXxAbiwaXKg-I<t~zgF#a%>_4DSMJ+qXJ=<;Xt;6h+TP`Iv)_dNlmGuw{^Q4w!s>p1 ze!X7*{{H^@H#aukx^-*SDy_VkzkdCaG*0W0GJSPrWw21^lJ9;(4bKhv6Yg3tfBpJZ z#P#ZxD>t-1e7l{We``zU?jso{T}L0;|NGdlH1Wl~z143%-MDds-|k04<=q=MJOV>1 zD=qzP&2FywbF^EWt2OEIv0ky(-Me<(_#3ysE_PwSn&|C)ktg`4b8*Q2Dp@y?*mgxg z`0eD)pR%v7Gc_^U^Z(y(vDTZF@Am!uc02yhBk`9nU;h67{`iw}0|AAXF^``<4ULPF z6BgcF{XK80mucCXh~|R_g7>Xk_wLTl;*~2`n)ohXvgFD0=d&$0?|FNByT8^{FO^Ai z=Ey9*s4@9uOjgg{Q}Q+y4uMl*^tNw*cs;)U?bD}U?^VCwxy72{q0^<EIw~qD*Vn~P zojUdG*|U<8k|$4|yn6NOH?G%TtCj{yN=thOPH|hja_w4OUES2{SzB+dTD5A^rcE6k z9h){8g-0i?|McKNLf4{qcXlS{A2!XtrlO*9<k+!$dnzwqoy)`_IBDH)6`_;IdZlY? zYv0x;U$}WQG9aMf`MJ3d9z0mEV8O}B>cJvM|GqkK|9-sIR5y2baWS#FZ#UDY>&KVX zy|<aV|JSS4T&<68Y)lrLz2UB>zW(~d?fm)?8x+jUzWw_8dYz0(gF<3i>2>VIPU;%s zi=8!-bsw((^Wb2!_jEnc?xRw@ZhF(}|Ns4NHCNBpw)WSTmp+NJmhsEkym<XuT3kFl zD9EVr(UEs^_!t@;=ASc7+W6z-WOeW9dc1smVJkzH`_I?Y(+gXD)r|Y~*I!4w#ogWA zwc{>jm?*pTSX6ykQTlMsoH?I9ec~3^v$!er@07SsL_ko`r?=bh@B8=b_2G8@`uBUk zAM2Nw7Zptn^vuh9w<>gX+POI|gUW>*3Nk)3)bVi1u{>6pqak4R<z+)k(8>_K>FVn0 z#`SIO?c(C%ySICqxw^R(?LXr0=Qr*2Q?AxSy}n93ll&N@q@<>V6%`lXy{ngKQTOM^ z$H&L--sQS3V_)~@#6;zHd8~mGN|+V|XyirS+>$wY_ia^=($dn68#g9x{PFdAe0sgy zmh$)aHf-3?(7>=XXlL<rzil6u&#zk*qSekPt2Oy#-RIf&Bd&|d$^E<NE`N58W$~XM zA1AB%CTZ9F`jYA9cI<rJx6Kb8JgEP3ygnx@YmvsPg$oreEPgyWIoW3>E4P@z+_PuS zoS8Li)|oRtOM_-knsjM-yM4jV;)b@}4|yy+cc^C_=@4AHbm^P<iC_@EE+#WOJ9=-` zSN*z=+-W;6W~^De_U)@zzdq0ZZ<BPSLx10oLpf&k-|v<Sbw0_j|2_L=PTij$g{i4a zOaCS&CQerK&C1I&n|;=5Zr|F1e}8^<i|JN<c;FZvef!i@?dNA_AJ?(3{q<!-;^D09 z?Be3$<2{m}zq|}i`+1~O*nf`2!L>i%+}vEWb5FScu?Dphr?+qC_|ALhd`tDBHIv`P z|Nk04^ZM1RSL^EPuFcN5xk*)7`EZWe|MUO<^v|DvU;f_*cC-F9t*xyuzg9gf_4VZq zPRz~K^}YQ4{r&W5_LZMnmc2aQFK=9*mYUitZSJQuv0$;V=k@C!UW&4bl}(uAqEz|q zO=Nnyx@+Lkqet`id_1-yaIssjROyQgifI<H85u7wE_Sc~efz%G(o5#|DjxgS|C)T3 ztGTIZhIn0Foloobyt|7st3EwBc}Di?^|<P{Q^VsD+t;j#-2Cj>+1VdIe!O_`Vr|`) z4?>g9rC$4dDsp|&-5rI^kw=ZA=bZJu5&7iVxw*TOj&kKOpGo^X!!X(I@0Z|zXJ^_U zP1+c>_FC3fi65!w_f~(OrV|NjD@AY5`}^TA|I3#zpH07eW66>wmo8mewrpAXy~^~9 zi(J#5*QI~{|L^|)#hJhK>wj`r2XEcE(^5&PY0(OC{kSDdmgq!oTC!))pZov+-oNR) zXU_+}H_;aR?<N|qzq8oA|3+x^ww%m|9NgTCWzLGF7YkoIHC4OUE!o?fd-swpTed7* znE3P4(?7F~duu*CXuOzVGSeq8Fz`p^2H!I~Yu|3Yo-u1*_4mBQM8(a2j`d0}UAk0O zR<^FL?%=_Lc6N4tVJm`Grk$TRciObF_xEhO7RlLEd^jo|Z?M|#*Ner={pZ*H`}w?` zU;f`y{rZzWOm2ZwLbU$A+x@=k=Ya-h&+D?7P0`q=j~^>PT#&hI_3CU;XZYHhn>&ls zBO+$(-~azer!c>)l}YX`lj_+8-%acP{ZVvoE2z(zI)DEDjEhQTHZ%90o$2=L_iuMs zS5XlWpV?-*+S;d2E`ELTq@c{!sJ*qnzrDP?+<(5Et+8?O!6w!-pVH6I`}^zqem+i4 zNxPbgy1IYj@ih<s%(N_g)Z(Mo-Py^>!SUng`TDrPK*zu<JBy$5$yj`7xBrv);laVq z&d$@*bgSR*{XV1reDwA_+qyqLHY6UNG-=YW7Y6JWJ=Jdo)1OT(wuqLopXjmVV#cS> zpSMQox(1#-d)C#}b-DlivaKsmo;;}?zRqN(&$%zYKiFM4%1^LV8#gY}SQ>Ov?hw0t z&4+{R@)06^U0uK4|Nr;?UFeTf+Uwuk-(Ua#-`_ijK7RbzFK?gr-=^RJ!*8k2r@oke zdAX}OJ#Htgt*oh@*1h@Ok*2WKdux7v+M0b`qsyx7&5Rhm`Ig1YKF>B5;c`t+e|~wn zzpR|>@3Pc)UkbxFdbbD_H#RnEhpkDlf60CH)6>)8YoknSeiW3Ox5&J>T-qMC`tGjM z*LQc98ygv&I(6z^?f2MsTHl<Nif7N9tJ_zZxY?}RSEonL*2>P#&fdQM{=V9FetAD{ z@5gKt4xg3e<>ghHm~mo)qMoeg(U;X+AA{FAJYTZOlAYxX%cOPIGb*1h3Cc`NOmuN^ zDJn9uE(~^XXgFHnTDEP+i4z|0iZ<UolhXcG?b?>8x38|Qo;+#Ny7>L;E@tdlJ?G|} zMJt5W{m#rVJbd!@tDM_!)|M_4VmROEzuxxHIql<ml^-9uTDymbPoF;h`oU&)emR>T z58LIhUAtCRQWCSj?(g64_xG2)oV3?>P5G1=GhRG>y0zx#r<N9$l_95MQ}c^A-@J44 z=FMx@!a_s0CLQhS>gw{h`?=)&IhF=@=SyFw9Nkl7HTPWq<3B$?Pg#8PQBGb`;)Ml{ znwpxWrKOpfnPRKo<nAke?k6ul|G<F*OO~k2TDCrBr%~!Dk>~xV<Bs#nS_!C__niJ9 zVZr>zV{d|%me#X#bFFi37;KFA^J?|_cel2#-n#YbpUcmKjGh$zd|&^+`rFs%^Xt#8 zGn(lm;%ex8c7}Up%$|ygvDQgPIu<QbdS<%)7AVwbo4sAT{a#jP=F8p8EZHwEH^!!| z-mp1N$>N;N=iSmw%*^Kb_s+z#^$V3NtH|;w@YNr^o12-LSz229rpM=6R#sM0QqsMu z*J}?QI^@{Q_O+n=ftHHwhlgd4I9^=%`XT&|jf&98Z*OmJ&%J%DX4TdP_s-q2lla&K zrq>;n6%jeY6H^)#6*X)7_VT#6d0(|`yzac6Q1XD`@>Jyo&hC~U&*VRge5~`0bFzr* z&mTVuerKPbZ=Wu<$s5)WYyavX0@Cy0bRy%2mh;wm`OfQI)~??F=-an%Y4O@qPwoHv zHvi51`}O~AT>}@p_dmO~x!~cUJ9lE{`lWA-e-`*C`}(@x-d<fzO-cK@n)Cgw55Lum zpFddNy1@VW!X3fqcJ9`dTNv)waX7y4^MwqPc7AzK&nh}PIyd+2v$M0)&(1n3`{~S$ z&FSa={r$ajbI!)M_7xu<Y)U=-=+UEppQi5*u;tc_k-qk0y}*~3HWQE9i%QOysqU!u z%h>h%yk=V6(Z3&$%gb97Jox$fxz^OIo10Rvo&U3K+N4RJ-rU?A|Myk+)~#C`8yh#L zpWpUwcc6%A>8mT1pP&7`z5nm*vtC8T#ee_&Njo>^C#aGP*`C&VaBCv}f6*rO=;~`* z5B<IVX+>Kl-z2|@tB)U=CjP7OyXNe4(ON72me(`bi;GVDe(=oTs6esbrpnd_c5~T3 z9<W<>TuJ$T&cEo}doH)kD4u#$v}ws_5vTggySP_AKbv+>@!76M%U)1ttw7WIe2!_S zT;)pldxBrp--$Na$#TdYEIe@L@WFj$`N=H2wO0KN)+Kk7FRm4S#JNTMvXhM%|B)C) z6W{;w^UpnEJb9+1|IOj4H<|9pM|ds0^ypDinQru^Wy{nQ6%{o!Jaoj`+uQT+?z*~* zr}^hrt9s|nn>J<4`uA$}dYx&XZ8T=xJ-yhyKPf3G?fksI-}nE&yY({j1G_tQGGC_2 z+wU!spHTDRf#d5%=gu6sdiAPl`Z<}IK4G!3cduMYF_8E%U*N>~6eC&7A{7IJfc4jl zr&}8zm3YR)d_MiJaY9Or{7=J|JNP~1Y$`UC2DTd)1d3oEHeGeQS6fRfD>wJ*>#y;3 zKU0&Fl{a6Qsd>ymT!MqoXr2Gg54|k^d182G`Ya1uefjd`Ubn|@Z*Q-@VX-%E{*)<G zX3Wr-ewv$$Yep;Ia*4w+2?`u{=ATe}_Ul%^=kd8SS8v*MDJ^rJ<c@#qt@PJ_`t)hW zj2U-#m#+?4wK4g)6c5|%-31mu!!d?T)7P=J2lq_05|=p78}MuS4EEF3d$yhu5$ish zwKZz>)ldE!N2c+^hnc@>b+Z}d+{@g${d@WST60a!PTgzw?tudN-(~y1!Q1_3wZFdG zQ~d0iX>)aV%))>TcR9KiSy@|W&Ptod@bu5!%74|5_Ljcfwtf5MZ9S64#~z*p1)XuR z?+k;3V8=%&Dk|<Sd%J4Qnw-46b0<!C`1!3{w{F|L)}v42uYIZ78?-WIp6epmIIX7o zG704(J%fMJ3+_~}(bd&WOiVme^e=ifxbKQS*|MD1=jX3qzkdAqapcGm_kKCcoQA#D zYrlP~dvRf*_jJ9D`Fq~HdDGC)z;E~CK&!E;%--AmpKm-*{_<$)>({SOPn%<!eQj6i z>lxR>*T<DsDA=pX8XJo@KfibFP%HQGUg`8=F?MdD&XmW;diU+ymt(zScYub-os;`@ zO3KQ_L_`eE@8##>N}4Bqc2D#T&0{)diR-1)^fs_^iyb+3jO&ZwyK6u48;ag<^imP} zmMr*xZRo6Ju1XX4@2?LD32}5hxFz%QrcIkFZXK8+Z&mW**Vot4(b3siSu$n^p3M!L zx0juj_3yj#{n7jDYGY&XwsMPq`uw^6|L^;sW7H3Pc=9~?%e$qgr+xYMEp5AK_fbCn zCD!|8wwW`Fy9W05_C`iVg4*)AxwT(jTwE8s+ec0KcTM$kXzwk){;%n6Mw^ls0fB)R z54ZErotf0LZ5FrBi(Tc+S7t`9Ui0M1lWuW+tKdtZQG2EIeWBYcmrt#KU;OM$<i489 zqM{-%FR#43b;j~O2PV(&zsNs*o$;>8C1-eI&ge35<LbJtd*`(Nx_;aq3oENxZyB;o zW(g|0$=Fs+Df+S?BMjapJNbX1kHDP$jH^JScUF70o(j?snLBr`&3DyrC<A>@{G2j3 zGk$xw#p=%QcXxOH|6c#!+{Pwm^;N4Jvw(SjYkKN-l+3+!nf(~o%;$3$r$=47bZOG; z*{`2IE&ci`bn{IaY3bd0cX$1o{_f7s!y?_iy?>wA|4ZL|GbScRMnvSxlas>L{n2TE z-j(kc?sPdn-+uef%QtS^;FUJJv%7r#rcFhsrf9ytzW({TO*b2IZ*S|Bv)#3N_30e5 z>({PbGO2xc$5Q?KKgfW{$(frUTK?~-J^s+pNIqs=%+93ZwMXp(YHRm~Xr<1-u{K1D zU)Jh~SYB@KQjJxM79DzXM0HE<?QK`CgtR(+yjy<XvRGkn(MzM4y-o)2LMwjcH$<KP z{`Se*tB~eP^KT9bZnPoA$KR%`l|E3sd~0<zyBuGB+~+$=<)3~^nCUBqzwi8hap`NG z@BP)e85yA2zoUoFoH^q=+id4j+j%QDZZtGEFTc4dHEZjx#fz2o_4})tzo3mA{@(x{ zITY*dtuSU_5S{^A3s5@i?6Y&{&OJXr|NfrJ&j%WrMMXu=<a5getqfVYa^=mNH`CA0 z+j^bhncr*k`!$E_4%a<9GjnV9b-S7$1_lNj)T`OE&zya|)O&i@(WG8C<>{yQ|NmD# z*Khi~d3LqGO8(`VN}WB{D}BG}_1c%0mz$fJeX@~1{7Yz2+&$s%U%&QtcWY~E&a^08 z<l4AzN6GGke`~E;oeEELC7omX&l@n;@A>h<e}5{w&*t8Xy1TP@d4IouLPA1NkdW`? z@O3dWjZ(WNzdd>Kq^7=p`sS0n82^+<RqrUDeq+vyUK_uAd%$(@$K&$<Uxn}I;^OM+ z?frZ6d|g;XL`H1S^LI8!tNr)r>)p*eP^@B;B+~bMi%UU;pKQ5+)BbHMw?F*!f>X-4 zkZC2GlR95a(~{=-0>5&DU-vkNuee|F<>=wMwWt4RPV`vjGqdR1o5*+JSHx!j`MSP7 zH7qnF<jh>_@*5ixlQ#ai8XkXlYj${cw)T0oH~HN6Dxc4d|MzM7o&2WVyLN?WUA?!r z`losNzb~IZOIw%aL`BV-d_VVd{ogy2rK-9??zs_syuOuN%8>n$*qNKZKT30kyPJOM z-@Ms;PVdH|r(TOMo{&uqjEcH-;lhTRpGE)9#>%eZWM)Zw$69BvHrIQxlx!bZts$)c zq%{}Pe|q+v-DdV~s}SK6&py=6IlEGyWqG}y+RdClr;f}F?6s9iR~PCuk@Bspv-_N0 zTwEL&7--)1&%!=LxT8f++T!K$CB>N`i@hJe(P`UkxFzcC)6>(}$L@9uys|O*_>-ca zXJ#7Dy+7w+!HQ)8Gde5$ivKT;|M#a!{nMR__7&T|JeE}Dt!|At=N}#xCMGBt7#4O+ z_w3y8zL`cx9;y^xn;juxTUAn1V{>_}b<K~0s3@uLweJdw-JG49JyfKOQaV1n^DR-b z5IOUsf5Y**KT|o4R|RTK6%!M4b8%5oSKq8`He+MvowGLz%O*~oc<1S}>HbSM-#aoZ zY<2A3s?wmKOJ84KH<jWopK3fiScPxel9!Bsqw}WUsCgdU&gA#9;pkqToIA^t-Ay-n z&)Ar`X5Biy_Q^*g^ON>2K61oGUw{46)6>;eR6Ldjz0<0mJsX^HwrvB=Op0oUg@lCE zd^)LaYp*=7q1OD-{=D=HdmhW5czu6i^mDCl?IYiIgtsr2(sY0PMusnau|^iW-*Dz} z>drU0_wt)n?=mGmSNS(1d1IyfrJpJ<BYyRL6*XF5{cVdopL)rsT$=>mC!Y`Z?qsa^ z;kT)_^~+yz_j#w2&pZ5&muWg|8*7tXs`Kpkl+#b&@JuP%`RDU_`}A<b{h?aAx~BVO zdW%0kaxGiC*V9MduErww)|Tz}s#Y&udi36Ywa-tc|NnFT|CWe%KAUr|y?++0FCdnF z`|oD6M$?!JHadQN$L)l>6W_ngIA?M@?(Yt>A2(}$C$#K;{%H>PEo1v<!S=OkVw+ne zS6}|TY}wMKvX(_po}8TAEv~;Ua>24?&)#moU-$iP`S-WCj~Bo1skFMaG5Pp3oybc! zZk(w3{LE+b&)44%)N}K<+sSgwP`4NEPW=2bgKzfRn!gWJRG>ne{+F1vpDo)|S0Fcu zkLAqLjaH$dp>LdZHM%~1{P^(O^?CO7=X6r0cep6c_1m6&obUC+w(M(bJUu)*dVBX) zepd7U3~8zCyMH0WWb4+gOP4M^XL9@GuY;8yRssh8b!uYgFJF`~yL~l1uhIF38xzZ! z$@4ppLM)B2-@#IAC1BQHt0wmU^2IqhX8wO42=z=nApWiIp-bb1h5qaePY%~wHO%|; zB0Y)GHSot5uZPYvg$oury!h}^6ux=|JS`!xZO0CaXA4&_GBO4)_tVwX+!%LsSK(u} z&95FE?f(4ith8Otj{W=pw{QxVSjm3wwyd6g<ml0-Po4ybn3li0BdQ%%Ae~?~8#MIx za{2sE`RD#<igjPj+8Va{sKNTWwk6C5Popjz=$Eri3eUZ{X=$snj!sXJiTRwfz7e2t z2&rCOUEMd6E?v6R*4Fm)^z_g9=S)5wM688*c>KU$PEYnG_sd&6RHTqwI5$G=?Cga2 zW-Z%Ue7Lo>_2=*3#>IzyXPce9r*^0I?0ozB6B88Knj2#$flHc22M##=!yKtuoqwLY zK;dPB3|q6Kico7?+ovfnA5JM#n&`3kqQQC1Wg4q??%cUzg~#fvyKY^9G-z(k`NQ{% zX%Zhx{{4NmK`TR)CO&!cM55R2oks1uKP6sEClwWXS*HneN3H$#>FMd~>tYvcyt=V5 zxoBt2vokZ#<(~@xH$|>}c65|?ywv!>aPozzQ>VJRxJ;QkHFABD0l#utrkC}%pGRXB zyZ86?_oweF1@)`Fy&r#Lm(4quk&z+L>EhhRQ~0-Fp|yb&56gM*AidYpONR~}>gecr z@+2kA$l}%0KP7h#y}45WE_>28&*ap3?Yky(>#eJ+!_`$)WB1p^F1}b0Zn@dgH4w6f zhpqgP|BK)kml-WXv_iA8vdYTLc7td9WMX4u&rB&}=a>8Q;V^%8cDA*Z)w=lo|Ni}c zzxl8JYxL2JXNnd!)hW}k7fH2cY6pZS@pVj^JUKWnuI}L>)@S~6p>^x2i+2jl%r_cj zTv#w=%9LHZc5T^W(jEHE>^`>Y)=Pda%Z4_=e-b<1N%)C?W_hs8@(r|*W4XuDpq(-E z=FB<s$1?NMlH}ukrHkjCIN{NJ@IlSb4<9}}dh{so&54;+lO|7oTC~$?;fu<@4>Bi| zT<|^KFK=J>XUFd7i?jRW?dzVL5G>!$^owN@U)9Zfd#ev0I>f}pG{x)bxw+OipU$uQ zwK8a>j8(}BAGP0S^Xr@gL(<aHe0_b>(v}6S^zroExZ?T8$H!NPua`5;x-vo0Ij;Wi z*Z2E=_eI8qhl@)~Ym0Tq*Z=+c>Qz?S!Vs;sD^?`L)&G9GU8u9AQWj&%;B@hKA#w5P zlO`n@&8+(E)4=X{$x%O8LnQs&oXTHcG6MrI?*DUo{~VjjNsCs@HqWp7@vvQ0RkdH< z{@?5P|5oMiV!9Ub$yf*o3Kl*%&=|cvFS2~uz3TUS<?DVtytLH2U*29%LxY2ZBVpR} zr%&JB-~a#N;dcA~KhIxZ6Zv?9EolBmOAEAa$o|h^`-mz3AGXUc^Pg{5`|FFcd*6>A zKfav%*zE3f$x%OgQ_9H~7Z+#F>g($A^7OPUe<$M_s5J4#(Qa{2k0vv-^6Av@MT-~z z)LyxEt!?qMp1AeXPd|-|ixXD!nQ$`Y%&IeI&YU>mVQ;^`r>7@>|KDqg)nRL+OiNw_ zbS)Coi8!G9|GEAD%40o}udlEF|KoB0?)ohX0v=W`QqhO~7qauq1&D}BNmYG$aq<4Y zZ`*@be(5#8_v7;Xe@Eg^u8rP)B*}1gUQE%>IhBeNJ?7a~U%PqpWPE5qfWYTN=g;>? z|GTizxoGE|U%|!#oSy7^U*6kW?LAHB=DynBYooV=Lifv;lFc{Itnu>l($dw<&C05J zKDS&<H|mJa_fMN@S^K0+SFK(9_TJuVzjxtE6Sr*NZoGc>tXXqzru_f+_u#>UoSdAw zxw(GtSX;O~+4rtoy0mrCitBOJy~|$iE`Kj3CT4Ux|IQ9jyYAw}htHpj%gCI$Co<V< z>6>ug7_F&U-`?ER4qvyY{QbO}Is3}qO4Yyeon`X!wEq4j8msp1t^NP+?>Upw4-XF3 z|9LFm&L{ipob`KyvusU@FBh1vy!z_x?d`_fe;OMbi|a%j(5e6S=H~kPzpp1unDFp$ z`}60|>pvb9H}MS?*;@Mg+T-K>{L*GRnwlpUX*C}-D0*_@<Ye{zpH69OYHI#TTypv4 zx|p4yiNBwppC3PV%<5*8y!?D&bw7=%ry@6}nVOsLuG^s?Ve<Q75<}9x9Oj=q7AJqX zcrFcUJ}4kA{(PI+*WO8!gnHdBU%2q#U7Lfx^CiWXGMnuJA0O|}&(8-XuZxS_?_OUQ zx2@*qr*3imU%!9H@2$FeH@7jaZHe<G%Qj(Fr}p3I>wIA=3uV9b?bu;4OIcU9H*&`0 z$%l0dUS3iy6J8l|%CG&TZe(!q<Ovf5L_}1?x(^>dygl!3R&3kC0F7Pd%o;o<9#$_* zK{F|pFCQFizQzh0J@v%4-skP?Z-*F~mNdsbe*9RuGV{ZOgV$IuUApw@)vFnjuixyf z{+?G``?rl(+O1DUQ><HASvh=d)YWv~wnipT_P_2*6LaqGtG&G~*GBlysT8BFQFG_b z%QKP6zrXM9{IkrUD7*gV?r!rJOHZBhnw@&-(xp9n_kRBL=}qV(%z5y4%B4GYb8vAL z)kUdGJeW{&A$v<y?p1GLHJ=TUZYn}AOLoaxm)X?*x)NuLIi`~~|NnuzuA!l!9v&X^ zWjF=cJ=yoFfflx0THx6HMl^ay!NVPek4voP9_CVo&0ybD{C+1^Lxd|o|9xDxt$^>7 zcWeh7wxpk*XMVrt^0QUPjvc#m=T7SBX)CY3>g(&<v&UxgNt4P?PwMg%1=wn>3Yu32 zFF!Zi{QR>m&v1=8{Jrm?z?qhND8&WQ)N+O_^B(9*h7q375Npgy6pC1sIcwR=c_IuS zOgyYMq?patv@SfRmvV}MqxHmHUWWc-yw+bHJM6fyoLTzE?wl7F8XqXU1h*nLoQ2FJ zC_z_amqnJ}zp#+G(FqbX2ik9UI=AzI$`;Vl_eN%)aM0Rqlb(qJJm2{O3m)GS+;pMX z!>YfHG2)89KT{C@E_To73)dLu9oTnr?eTkjH-Z`Owk`SW@}^okKl9ac^+ro$6W_;Y z8oWRBwj6gn^D*H(r``2t?+GRISPh>G9O45l$a54Z_H(+?xOzf~9J}Fjo;j)ooRIZ` zpGAKBZCQQedF+neiV6%^m)$CMc6TqfymaZ(j8;oa%R5Zd^<tCECweVCdi3a<sBI~} zzP?UQP5}WEB6Rrp`S0&4U0o{K=CshF?9Gh5Y9FsS|G&~JZC(*|<K8{L+eT?;X3U#w z%+Td@iSyhv-RP(|tBMZ`N*fOxIB<5h`RDLU7-Pv!&d$3pO8l$Z;hUS8$;r+AICJ6p z_4?68NK5#(O7k*rXjmdFAulg~(z}_Rf1BQfY16{O!^=NC@to)N?%v+$`1t*ahubD9 zyLTOZbmGK`(A8n3iw*yLEtst}(c{Ma<{R0H(U)%Do_#k=N348tB7@k3k|h&8RBmt2 zzrQVa_Q{k@;cjY^S6+Sf<x9!pixt1Wz0G^Sy85fdWv7OFtxFc?+>?7%@3*b&{k^@8 z`k`TAw{#{?oA&JO+qu)Hr>_^%$3D2s!Ns+!{C(W{*MVA7^|lIt)<?3qt-czz*Cg=} z%j{Ix+zV(8+}o?dLPDFeudh3G>eRDm&w6@#o;-Q->Q&b3*pSfB)|QqJTaKTs+7a() zanq?G&Sb&lb8kH7<P<wNG(1}B*vxiQdt1T7Lxqozy)3b67xhw^)GKZN>({SM-~a6d zjkw;scki4@&wja?KG)ugF@2GFCZl$3o^AELn$NzoS4&At7Z(>#*Nt8lw%Xdt>eHuB zK5CbroSYncm$lwjKW<M(ettSPzm&;|)34S4Z~nAJU_m+W3p?4H%lzhA<=@-0ZJXKa zP+Wz_x_3?c<zTJc=g}M&b{oj=U%tR_dgtqcO9wn(TxMkWSume(&ZP?%43dxWbhpl& zIdisIZjpC218Di$JSO=gyBO7Z=d>U#WqTeuM_!B#vg&mCfwRlr9js(dhvrKDq+`i{ z=d|U=9#r+P@^9JjxcxKpI;TsOV%sJ+nQyjzGt;r1Z%+G?&lVikavhd0<a#E42<Whs s+mUfF6qFbDY;HI$x{DpOK>qjtJ#*IS^KO~~+S<e5>FVdQ&MBb@05e1@{{R30 literal 0 HcmV?d00001 -- GitLab