From 3847daa32a7d6fb2d9c1f88845f55c1bd58352f2 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Fri, 16 Jun 2017 11:44:54 -0700 Subject: [PATCH] embedding achieved --- pitfall/fontkit/hmtx.rkt | 2 +- pitfall/fontkit/subset.rkt | 26 ++++++++++++---- pitfall/fontkit/ttfglyph.rkt | 45 +++++++++++++++++----------- pitfall/pitfall/embedded.rkt | 12 ++++++-- pitfall/pitfall/test/test12.rkt | 6 ++-- pitfall/pitfall/test/test12crkt.pdf | Bin 24331 -> 4474 bytes pitfall/pitfall/test/test12rkt.pdf | Bin 0 -> 6354 bytes pitfall/restructure/stream.rkt | 3 ++ 8 files changed, 65 insertions(+), 29 deletions(-) diff --git a/pitfall/fontkit/hmtx.rkt b/pitfall/fontkit/hmtx.rkt index 5bee0616..07d96633 100644 --- a/pitfall/fontkit/hmtx.rkt +++ b/pitfall/fontkit/hmtx.rkt @@ -11,7 +11,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/tables/hmtx.js (define HmtxEntry (+Struct (dictify 'advance uint16be - 'bearing uint16be))) + 'bearing int16be))) (define hmtx (+Rhmtx (dictify diff --git a/pitfall/fontkit/subset.rkt b/pitfall/fontkit/subset.rkt index 0414ab4b..b636f174 100644 --- a/pitfall/fontkit/subset.rkt +++ b/pitfall/fontkit/subset.rkt @@ -14,6 +14,11 @@ https://github.com/devongovett/fontkit/blob/master/src/subset/Subset.js (send this includeGlyph 0) ; always include the missing glyph in subset + (define/public (encodeStream) + (define s (+EncodeStream)) + (send this encode s) + s) + (as-methods includeGlyph)) @@ -38,6 +43,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js |# (define-subclass Subset (TTFSubset) + (report 'in-ttf-subset) (field [glyphEncoder (make-object TTFGlyphEncoder)]) (field [glyf #f] [offset #f] @@ -48,12 +54,13 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js _addGlyph encode) - + (report 'in-ttf-subset-end) ) (define/contract (_addGlyph this gid) (index? . ->m . index?) + (report 'in-ttf-subset-addglyph) (define glyph (send (· this font) getGlyph gid)) (define glyf (send glyph _decode)) @@ -76,11 +83,15 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js ;; skip variation shit (push-end-field! glyf this buffer) - (hash-update! (get-field loca this) 'offsets (λ (os) (append os (list (get-field offset this))))) + (report 'updating-loca) + (hash-update! (get-field loca this) 'offsets (λ (os) (report* os (list (get-field offset this))) + (append os (list (get-field offset this))))) + + (report 'updating-hmtx) (hash-update! (get-field hmtx this) 'metrics (λ (ms) (append ms - (mhash 'advance (· glyph advanceWidth) - 'bearing (· (send glyph _getMetrics) leftBearing))))) + (list (mhash 'advance (· glyph advanceWidth) + 'bearing (· (send glyph _getMetrics) leftBearing)))))) (increment-field! offset this (bytes-length buffer)) (sub1 (length (· this glyf)))) @@ -92,6 +103,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js (define/contract (encode this stream) (EncodeStream? . ->m . void?) + (report 'in-subset-encode) (set-field! glyf this empty) (set-field! offset this 0) (set-field! loca this (mhash 'offsets empty)) @@ -99,13 +111,17 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js ;; include all the glyphs used in the document (for ([gid (in-list (· this glyphs))]) + (report gid 'adding-gid) (send this _addGlyph gid)) + (report 'all-glyphs-added) + (report (· this glyphs) 'glyphs-added) (define maxp (cloneDeep (send (· this font) _getTable 'maxp))) (hash-set! maxp 'numGlyphs (length (· this glyf))) ;; populate the new loca table + (report 'doing-loca) (hash-update! (· this loca) 'offsets (λ (vals) (append vals (list (· this offset))))) (loca-preEncode (· this loca)) @@ -116,7 +132,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js (report (· this hmtx metrics)) (hash-set! hhea 'numberOfMetrics (length (· this hmtx metrics))) - ;; todo: final encoding of directory, with all tables. + (report 'encoding-directory) (send Directory encode stream (mhash 'tables (mhash diff --git a/pitfall/fontkit/ttfglyph.rkt b/pitfall/fontkit/ttfglyph.rkt index d54ec1d3..d60ef7c1 100644 --- a/pitfall/fontkit/ttfglyph.rkt +++ b/pitfall/fontkit/ttfglyph.rkt @@ -1,6 +1,10 @@ #lang fontkit/racket (require "glyph.rkt" restructure) (provide (all-defined-out)) +#| +approximates +https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js +|# ;; The header for both simple and composite glyphs (define-subclass Struct (RGlyfHeader)) @@ -59,8 +63,11 @@ (unfinished)) ;; Parses a single glyph coordinate - (define/public (_parseGlyphCoord steam prev short same) - (unfinished)) + (define/public (_parseGlyphCoord stream prev short same) + (+ prev (if short + ((if (not same) - +) (send uint8 decode stream)) + (if same 0 (send int16be decode stream))))) + ;; Decodes the glyph data into points for simple glyphs, ;; or components for composite glyphs @@ -76,7 +83,7 @@ [(= glyfPos nextPos) #f] [else (define stream (send _font _getTableStream 'glyf)) - (increment-field! pos stream glyfPos) + (send stream pos (+ (send stream pos) glyfPos)) (define startPos (· stream pos)) (define glyph (send GlyfHeader decode stream)) @@ -91,8 +98,8 @@ glyph])) (define/public (_decodeSimple glyph stream) - (unless (RGlyfHeader? glyph) - (raise-argument-error 'TTFGlyph-_decodeSimple "RGlyfHeader" glyph)) + (unless (hash? glyph) + (raise-argument-error 'TTFGlyph-_decodeSimple "decoded RGlyfHeader" glyph)) (unless (DecodeStream? stream) (raise-argument-error 'TTFGlyph-_decodeSimple "DecodeStream" stream)) @@ -101,46 +108,50 @@ (hash-set! glyph 'points empty) (define endPtsOfContours (send (+Array uint16be (· glyph numberOfContours)) decode stream)) + (report* (· glyph numberOfContours) endPtsOfContours) (hash-set! glyph 'instructions (send (+Array uint8be uint16be) decode stream)) (define numCoords (add1 (list-ref endPtsOfContours (sub1 (length endPtsOfContours))))) + (report numCoords) (define flags (reverse (for/fold ([flags empty]) ([i (in-naturals)] - #:when (< (length flags) numCoords)) - (define flag (send stream readUInt8)) - + #:break (= (length flags) numCoords)) + (define flag (send uint8 decode stream)) + ;; check for repeat flag (define repeated-flags (cond [(not (zero? (bitwise-and flag REPEAT))) - (define count (send stream readUInt8)) + (define count (send uint8 decode stream)) (make-list count flag)] [else empty])) (append repeated-flags (cons flag flags))))) + (report flags 'my-flags-homey) + (report endPtsOfContours) + (define glyph-points (mhash)) (for ([(flag i) (in-indexed flags)]) - (define point (+Point (zero? (bitwise-and flag ON_CURVE)) (>= (index-of endPtsOfContours i) 0) 0 0)) + (define point (+Point (zero? (bitwise-and flag ON_CURVE)) (and (index-of endPtsOfContours i) #t) 0 0)) (hash-set! glyph-points i point)) (for/fold ([px 0]) ([(flag i) (in-indexed flags)]) - (define px (_parseGlyphCoord stream px (bitwise-and flag X_SHORT_VECTOR) (bitwise-and flag SAME_X))) - (hash-set! (hash-ref glyph-points i) 'x px) - px) + (define next-px (_parseGlyphCoord stream px (bitwise-and flag X_SHORT_VECTOR) (bitwise-and flag SAME_X))) + (set-field! x (hash-ref glyph-points i) next-px) + next-px) (for/fold ([py 0]) ([(flag i) (in-indexed flags)]) - (define py (_parseGlyphCoord stream py (bitwise-and flag Y_SHORT_VECTOR) (bitwise-and flag SAME_Y))) - (hash-set! (hash-ref glyph-points i) 'y py) - py) + (define next-py (_parseGlyphCoord stream py (bitwise-and flag Y_SHORT_VECTOR) (bitwise-and flag SAME_Y))) + (set-field! y (hash-ref glyph-points i) next-py) + next-py) ;; skip variations shit - (error 'kabomm) ) (define/public (_decodeComposite glyph stream [offset 0]) diff --git a/pitfall/pitfall/embedded.rkt b/pitfall/pitfall/embedded.rkt index 2aa456dc..06f583a6 100644 --- a/pitfall/pitfall/embedded.rkt +++ b/pitfall/pitfall/embedded.rkt @@ -2,7 +2,13 @@ (require "font.rkt" fontkit "reference.rkt") (provide EmbeddedFont) +#| +approximates +https://github.com/mbutterick/pdfkit/blob/master/lib/font/embedded.coffee +|# + (define-subclass PDFFont (EmbeddedFont document font id) + (report 'embedded-font) (field [subset (· this font createSubset)] ;; we make `unicode` and `width` fields integer-keyed hashes not lists ;; because they offer better random access and growability @@ -40,6 +46,7 @@ For now, we'll just measure width of the characters. (define/contract (encode this text [features #f]) ((string?) ((or/c list? #f)) . ->*m . (list/c (listof string?) (listof (is-a?/c GlyphPosition)))) + (report 'in-embedded-encode) (define glyphRun (send (· this font) layout text features)) (define glyphs (· glyphRun glyphs)) (define positions (· glyphRun positions)) @@ -69,9 +76,8 @@ For now, we'll just measure width of the characters. (when isCFF (hash-set! (· fontFile payload) 'Subtype "CIDFontType0C")) - ;; todo - ;; (send (send (· this subset) encodeStream) pipe fontFile) - (send fontFile end (send (· this subset) encode)) ;; temp + #;(send (send (· this subset) encodeStream) pipe fontFile) + (send fontFile end (send (send (· this subset) encodeStream) dump)) ;; todo ;; (define familyClass (send (· this font) has-table? #"OS/2")) diff --git a/pitfall/pitfall/test/test12.rkt b/pitfall/pitfall/test/test12.rkt index f3b98066..8ea2df78 100644 --- a/pitfall/pitfall/test/test12.rkt +++ b/pitfall/pitfall/test/test12.rkt @@ -15,10 +15,10 @@ ;; test against non-subsetted font version (define-runtime-path this "test12rkt.pdf") -(make-doc this #f proc #:pdfkit #f) +(make-doc this #f proc #:test #f #:pdfkit #f) -(define-runtime-path that "test12crkt.pdf") -(make-doc that #t proc #:pdfkit #f) +#;(define-runtime-path that "test12crkt.pdf") +#;(make-doc that #t proc #:pdfkit #f) #;(module+ test (define doc (make-object PDFDocument)) diff --git a/pitfall/pitfall/test/test12crkt.pdf b/pitfall/pitfall/test/test12crkt.pdf index e5b8cac069909afd6da450b99f50fa9e9fce3d3d..22392aabdbea267a5c06e190499e999ef5e18d02 100644 GIT binary patch delta 2690 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 delta 22702 zcmV(xKPp`7_kZvE-uvG7Uf`ZPo_lrgoH;XR&Nk-)0RR>32N|rHJwF`1w0hsW0AwS7)~;F9 zGi%9?3-$^C@)dZzwQlRsj`fe8hnGrQ01E!T?v&jQ_j-ne!5-oGvN z-G_fa10cI*%l36cx83s0hXB`q<8|`F)}g&SgyTXG%l&x2W82WyksBZN)&P75-(TFm zWBab%>#lDp2KZ3~KoEB99NA&*{GtNe_XE6t5GbyQO~>sz$7*%UzoA(6KGwjCvM1X4 z`N>Z+t1}e^cglW=e-_hw*+2Z9?B$FOaefxBuPL~bJt_a+Us=sxVLd2+U^Wzp*GuT@ z$Sw*%Mjj$pfE8(zn@ zeVo0Aye%B0J%J^Ic+7(xWB@|K2hbseph>m>?84&^hiAb~eh8cKu#?XqA?t*Fc)yRd zLm1Bkpxo%oD%=yT|qybDR$Jup)^JM*Qm z0-VBLs1Y8-a|a%kP$@iwfBzYrqz7E&5hxSZVSN!;WNX1DJPT&w4ZL25_q_o=;X=F? zf)-&RXz+KH!sg5eGNhoeB=dzZBlD>+18T{wa0z)Elz6T~Dn5&UI0545B41uwZ^Xlb_xr#ol;izpfemRDB!l?w z6qw21GhfSOnKbzV%E&)58S*l||6S?t~GGAf25btRh zRzVQ%f)KeH-+csseDH5})Cq0au5Pf>w&S5?2c^Ydus;UjI!3dr#p4LWb3*~Gdly>p z-i>&?jK>x{hVWRA$5uR^!ecWY7vS-Lcz%f9M@PGCZRQ!W4;OTa0z^P!uKWATjRR*hrPMcc$^JRQdg zt=Ax)uFM~>e6?&HG}D7@hjw<&2NkkmeC~Fz;88`N&t@s1|DX)MEXqI;6lK!LSBf*o zkvEheEQL~kgk?~MPzlP+H^_@s2-ToQr~wT^Eod`egAQ~E%b^@$1ymr^gC3y)44JRM z2u6e^Fd@X*hR_V=%zwZF7KBv{TA>P|4Xl|j!45Wr4zMG1f&*bSI5S^>3#t*i!G+KR zZiHU&AoPJZ^EvpzhcEzsgh2=(tbt(W-+(*;VJ(Dz5Y|C0!Z6fjK7$B^5!OQlVHD~S z#vq#c6dE9gFb)j}6A(w3WUvtunSVhFk_eli5n(f=5Vk;5=AXzXn-R7_3&M72Mc4st znNOe-+7Wg^2f}XXMA!penSVepbR(PwJqY`t7hyk4LpUA!GJl5|(2sBcrX!pQGZ4;# zfz023aFv*ea5l_BI0pt1&V|{Tk6|8z^I;Cc1uz%kLYSBN2o}M7go|MT!X>Z};Zj(X z`4E=DVuZ_K3Bnby6yZu(hHw=u&wK!@VFki9uoB@AtU|aJR%hOab+88EFbp9afwc(N z!@A6SumOep7{&xh8+m^z{v$F~V=d0fbk;B?zyCOEZ6jtKc$(SHtB9uYqqPycVv= z978U7CBp0BDumyGs}X(|uF1RsH^8+BzX#VLyb-QP_0@I8b- zgc}k52)>{B1KiBuEpQXUTj3zW+u#R(nb+WU_#whO;717WgqsoG1-E2gg}dQagg=Jc z5dH-D{;O~g+>!Y`{1om)cnI!7crVt0Y?!20*)eo{3Se+ z`3*b?KS%f!Jc{sXcnsmM;Bkb{z!RBKTvdL7@HzM;!sp>hgfGBTnU~<#@HD~~;a3P> zf@cuoy_px`H}D+7-@@|MY7`8B)(FCzRsyoB&o7)AIR{08A45WWDf!*3D3 z0l!0d3|>a~M|dUkJiH0NNBAdycopGW@EXFm;SZVT;Lq?n!gt^egnxl!2>%Ly%sdP4 z!kY-+gFhjBAKpUv0lbayL-=#%8Tbg^LHIHJ1>xV|uL%DR?`D1l|A6-pegf|!{3m>X z@L%v@=4tp8K0^2zga3w)5q=JT%RB{Nz~2#m3I9O&ANT~}SMX1SU&FtDGEc%c@F~LM z@EO81{2O5gKF?4YQN|BhktnlO;a^xH)p!)b|M-sxvI2RbVqz9vrv~=>o&Av!-40ZMfp${J{@@bn`8Lx7`kR{`e<9z4ENH z_n&j_`4?RHt&5-lWfefa?m)TLglmZpIo}%OAwPx;sV7}zJ{cl=$ywwo;a9>R9Tg6< z!{(@VcpVW(lcUF3U9J0CVC$#@f9c0x4&iLQ2Y=Z~=8-k{%QNwpPYbU(${i+0mBYb) znG%0VG8yDWkUbE8uHn6&X#`0BE}sr>&3|jgThX`dfBNy8kIT0(S|;#lz#|G&*LWYt z+sC5b@-dFFFL8XNi2&pOZA4y4Te+5UY@8eGkt4o@Ty8VYrQaaGd=-269iY7Qb>zi6 zkw;Qqw-@KeF`NfyAn&>kdD-`nlih$E@Q%LefrK26 z-c3D+$Qt}Z2w_Fgi6vRcG3}7dGi}}y*HXs;$ARg?2OQHJ8;6Du6?oVgFN_>m8g?9l z`Aaq-T(HD>sAH)`Dvm5&+Jw(3pwB5_&pEIZpRiefe8Oh-1bo18yh$D!a2%3(=Pa4K ze%b|{*r52~t(R=9eIZF;b-eYktU5a-VN-f3nnVU>vn-$pR!XOrk_*3RDIn-e} z1WOMb;D5QChxQ*hU^#$zh<_i3$H!F=7+=vLR$x!iC(1m%hspjq?9zUh(?Tm;PL~tg zxwHp=-(4IUn7^bKTk2d|OZ&VAX^VOU2sNk#3cTps&{d6pC!UB@$&yJ~gURVM8LO-BCTBS-`};M)bO-(0X)-zSr6F<~u?x?kPGo_; z!%!7I3_3ij@X-aMc!cSo6F$RQ&CgKzp(Qico5P4RU3X;^XS`W8%G;$MjntR>>IiLr z4{eH?#Moa6Y+e;nlUa5`0u=^A99KFBF;oPIlicOR^&#V}}e+X6{0;xd!YAq3S25|ODRTq)m+&6ydo`%5{r)H_ zcmgVgwDILws$eBGmck5;a!TgWBZyQO)LLB%8yKd8g3^FqE5&PO{C$93Gvl>?N_MS+ zp~25?@$AKWYw$XK&Jlb$FJXU{hs6QrrUT5KH{x`(LdQoOtI*R5J+1f|D!1e_`owZ@ zi%;Yw>^waZ-l%tliPxpK5gY;vy(?ZveDRo_7-CvFGLvz=3a=Q;+i+y~NNtg8PF<~9 zT^Cuudc&$<$FQePR~(!5@T#SMk?7h`ym^Q4USDbHjVtxqe^)IW=-;4Szg|$5+_6E6{uJ)sIy}5>>&Wodvg1R-LDS+z_uR91(I?qT*An{oVm3D8na_l~ zS${PmzkBE?#IZMI3>j*Fo~>d1(t_t=hC&ODHZP90BPd3AAnz_-B$-#KQ4fe>{BL zSS8mbpYK=st%J)C)kfDu!-FaN`GJ6?zT4+-uQg4Zxy0`^_!5qp?c_pZSADcOS>x+X zf8%JXDlhW;OTr7i%j5x5w5G-u?+>2Z;_nYsx7M0X{-nKSuFGI)4OBM;O)X3{VK&FR zgl7?bJ)i${6apQ8G05<1aBLu2EyU;YGB%2%L1Fj%g-)f@;tH)HM?wRx!qUQWoyi#u zE?JJx+nm`+&J|unp6=x1yM#V3$03j66)KYz;IkR>IA0l$PLgvstXMU2-nCawiPw0Ylt|n0Wd<>skfQYMb8k)d=1gnjR{1L1)f}ByjR4Qr35@ppc zU(%>1zNEq!CP}r>PJ9Y15T`@s@I6(xzhFyQL3g;+5biD*77EU(?G>&(^UT((8;g{^ z_xGFkDio)GRrb%VDl2N#aa!!dMdvAD0lqAG6x$#$#8B8_yqGT;C8LNl^E9waGOSYI zB>~UHboJ0W^-irz>x?_K~E_+PLg-d8fiP&Id2NjHcl!$Btv1e0VCGh#*CNMr~h(!}PIEf*# zxUIUnZE+%d?wv8Cw|Dw<;qJPn=ggmf&eCw0pX^?a^RQUPBrWvn@cbo_+r06})-jJFeitsGshiertTF0MW}7`VD;$}Xu+}axR&mgux#c*VNyU9^7!nSYayvHfkZ@+hty0xF%f{boG3NHU8o zul-5d++<$+i)cj=ZT}G}XhRZzMr9C+NfI#$a_UlElO--r7%FE(+XNA@cvK{`t9m?= zg`{=Ca(CCtrrPNZRSuIzW%t)2UpCHv>@TyZj zNSyY4H1h@d0Oz9*PCg9&FkO7{%p^fP#D3>%XUU0XmYP@m^6b=qP zqp6BbtBK5St=5>Ubw-T3^iej8J^T&KioMhNEZ}7e>BV1{ks$4V79LVst!>!>mn6lEMncO+@6# zQQ2wN8fP!BotboaI+w;`3)@_Yk*ijue=p4Hv&X&qIUNgxD-K-P>S&sO6NxSE@c3t( z)U)Qsle-Gj2Q+ro-ZLzbZvWs?&SUy;?35!Ni=l-sw4BFKY>GfJsa%>rfGC;dB1v!o zAWnrVE|jMqm`|pqU(kewgZ|^E8-%^fZwDp=hBBX!uY{lAD6N4Mm6x&SkS%BBWf^;O z7;AVxhQpNE(7ui1HLit!#KTle6_{vi0WDjttzs$L)(M)1fmRqe_jZfIAANv9R4%My z3Gc+K(J`W)N}%FPJ_AVRPjCejZ`k~=6G*2o(3LcYoVq#t`ud%%3mX!PnjIH!vL$AQ zYx`rC=4WEzh5engDx)*W$>x54%QT&%rZUF--Xxop}PHVrM<2!L`lK z`^TNt#;RzSRB?KiB0Y7Co>d|}>2Gw53fK_|N#u=1WhnF(X2)e#avq0)$@KQM>C~r_H!* z-v$@OX${H>f1(x)Z0PKqw7?k@U7w5Dj2kx=6_aa{cx&M?YED3wcWkWQlV3iFB8FKM zHRzeV?Y7XO#ht!3CwU0aiE`8jtZi1PJBq@G!1`)pTaMs={I^Qxio$WPmW>y;vhVNN z*2%>#Waqgy9KU|N1V-oTIp7f<7s5DxJx7>5hrUfpA0c zJcOr?KP*gtKmIVeC6zjwN=J=%`3(4j*}TJ5glnXfYb7a{t3$@7 zDC8=CY9eW*TCCTH*y2Ur2MSu%O4tRe#nF0WQc*`l_85z{6X9q{X`xRpGnQA>8JwQL zj7{w~Z`l`Hb^e_03))q4zT3C(s-_)Rw)|l6?EOn3joyus8G$}mVw%CA1eORQ6e9u0u*IN*n#Cnl#x&mbaAymSuTso$f{3T-f2_xf81Bn`DD|7 zhx4D?Al!cZ^0Gicu6pb-l{^qA6LzN0C3?0F;&2e^aLuJUNdT_qvbUPi4tY1DCl!1= zP{c;IEKIdkwfL7qv{}fQ@^J#ms+3lga-57*BV>=2-_NTv0X|<_aO3I5@Exo0rs@!cK zS$(U&NjNxr{!SlRIAiq)_J!b675dYoq-*-=0y+K*S=Y=93psDAL0M}i(?wQNDM=6w z32Jd>Q1Oq;vT9~^%wk3I-E z5jIX$A`|1H2;pk2hU&SrR4UFwA__Yu#JF9cSUM>oUHVu%iLsK_NlQ+DCqea*&f&AMm|;2*`~Mn0 zGp#U>$Iqm+X_)ylWCm}&dI$zpZmYIXWQs_B26uFe25 zpX~hl9?q{C*u(jal3`PSAZpFH>Wh4(B23FvUOvHEnls?!Sym?UT-}(W*Uw%l*RG;1k%z4_j1vCUXMtOsk?61Pf zWX&Ar#k8V$3dh+5qchcL4P!J~oFJo|(pqUYmydF%msRv7RcHIl8D|z|HM8i@HAm}| zN_d4-v}wr_ZQG}Gn19-)P2VAwQSmBNef%+w1Uw)A16_aQDxyq(%1dmFU~5qLCJyW$ zH4JcFOgNE;P(>?$RQa}^LQ!4dIMGq7lt!)8YFCF=+i{$M?5nelqBJVYd`1pq8;mfQ zdnx(2q?)K9uQeiDpWGrRNPSx{%B^zcjMta@cr&Q<#@s_TLYFOVy8C#WcEhf=-bRzE zL|fF~B%I6|mHz(4=b3IlODPB^Z6zCWJa8Ab&jH^)id-sxJNK)&op!3e5>@_Og^^Ym z^G1oCR@nI{DZ}@e*<ia}J{UDC&rMYpz*J9O)Mo7-kk%7ucCEJkvy}GF$e+{B{Gsx^X759c7B&=~x)?1EAI0}%{c2gN9ATa$ zO`fDYp@pJMl&dJG73Fz!siYN^lM-q?Y3TdPnHoa}J|_+(l793Eau$AtI+C;ZU15CkcGOI-?r$w(&y<~qzBIx z_$@+zW4eqYF4{#t5$+WZ;aj{gbQpYyZM7tG`SR@ioaa+|DZ~G@y}w+t_gh7KKQjp_ za=KE&C@o~vOjjq6ZRaeHHN=9KFX`A3+OU54x%G3J9FC?r^^v(Lha)vtIJBhxf_d8) z_s9|t31L9)+uV5L>>WA&Z44$D@QTOJn8i@MpMq&YJ=AmBnl>&{H1?WkJH_~rbXp7 zqF8c^!CAU!>58E;vno5U^^w6;WOm9f6Q076OzH*MqWNJXd;#@&dtjNPzB(Q8!K#u z%bA|c4f|AfNhVNsVKy9}Na?HyLvE5^jBlRRv1V20hUvadE6zP{#YSKM#vS$ZDCOtX zN9W?Xd2Z>c^1^^-&cc$WWvBMtwr=r%;&r!8J9SyJAL-sp=}yN%?{<;?&dis>6-fUG zG{Y^_FHXG}S?hWW_DBf(AjCAp5XhMO!o#lBPc6etV0wO9;pe^4z!p8ODmt0nfkuN+ z5htsH)Ui^7hQ5PSrw+?aSZaX3YyoR=t+U6e)2mC1O3a>Ub!nwaoBBJ`TZ|U@@3rm9xDrTBdbk7&ceqR zonS4^Wy(;`^g%yMukPs;cj;*6O>Gm2O+5TH~k=b%kccZCW+&3k?piUS@~b!23df5IqxFDNH-L zwR3_rEb&RsH|R1`Bxy7SqQc8;Cz1xktO_nQam9t+q)K&zt~>p8x9$d&Dk&ViVWs-` z^CAJ`>XkRpwpOD4ayygdxA91t5=notpQweR)LK0G0xt=Um6Ab_X!z1kLH9#6EXcLKL6vK;TS$m^oZuG^!X(>AI^5Ui!Iv)N-&+%@>Wj7Ue zztZ*WgI$!2WiLLb#F18#{yP2ZvOqwgdgm=&VIZI+mBga-Q=C6VoL3{xCfG+qb$DbT zZEgi9PZWzbp&xPr|5&s&kF-;nx6FW z9?h>>DPE=NzmZZ^so$?m-~Tq}4lk3HC4BxsE#hQhy6j4hlS<-ca)uqPDHO*QFHMQ3 zf>tOv{}!ZWuO#c}#LJw{(;f*v?jW(D0~MDh3B8 z#=hi#yp9u`2-UQrnoCioVkpBAX7J~hQHwMSszr}Kx8jGmVOn&rv7{!N9Zzo403m%3p5|>AdZ=mGgSy zjf_%DaXdEIZPl%d;w@|Yyrqx)t*FSFm>FI&?4r)F%opTwq@4wuat@Eb@r3DrqLUqu zUJW-c6@{~wcph|KG|s{y8Z;)Gzeg#WC{$)gr->nLq5O)AA35()KCT92Mhd4mC4D?t zL=hv8*RGC4=QTO2+ZIOWttIJ4R?PIytXUe5nL;ju@LtSjb9XFHrdD=)Hm)pE7nKg3 zWVOE9+EL+Ya9}H}IAG5d-Ul0hZ0BQ@+ZzRuXPGtG*rRddw^YK*N-L}!uRT=*VnYgZ_!u*cVG zXe@a)g0V|n>s?F{t08ns+lfu4&r1H(4erg0^foH;B0goJd!3sHd;)B%vPAo8w5XS^ z33UW3>{kCsYVoR6tR&KZ)MbhFhfS4}?rn*57aI-UlyYv$-5N4gm3B6zy1G)SuJkfxgEQ2kwR!awW^IX_ z;a`r7r5bsPlX4VlNl`PK33oWqXjp?Zo78#S-8zQ5i}9wDarX&-nicgh5vG@MUsAcq z?hBw?V)rH7kvYl-p@p%18dxAMc2qs&k$l;|aB$uqo9*c8(Zyd6Yik=L9lG!v3GJ-Y zk@de+<(M^)eiug`9hAk%h%w4inkt=drss?8-AtPZ zLgv1V7hb?N8jz9q@ZBUv)u6MUrC^hP>GXhSxu6!u2XN|>!+-!HJxB0r7V+MzR(`M3Iikh_t$o=nCI$8Ur zaizg=WrdwQnuYVKN)46#r{ue$aV|G*@*Ti(HcGM%U=W?%6h&H6i|ooGv8$LimK3#e zz6XQ*J}T+B@Rom9QTu4e#fLg>{8kf=6>&7A?RTpRJf5N}zm$8OzqpHWEAI0sL|n=s z!TrAZzOa0MK_=J2QmKU{dF`REuWF{R*QGubU&+=ukbD>^ZVESyo6j*lo$=&<>77k2y;_{rx|*;l<iM^~>l@kWI4KJ1(h8q5bW++!Gz(Ot!pE*5>;E* z4sB!Fr4i+a0w((f;I6|E#P+-J2}n+grzwHT>4W(Rj(B)8}($=^3%WK^Bq6X=UsU7gF5-lVqUqZ=X~ z4=(6)y3A4QL&!XOkiIR|t&1C)*YtRbZ>OqTg~r-2P`7wUs|7}5ub?6yBl~s3?JbChPsi-HEi<&NsWetk)YC*17a*qFe?Vxy+hKo_1gKs`mK{e|SQ*L0O7?d5& z@jO*Yk<*dL^Mas@f7q^_)f(z=u=@HpbhgUF*1_d-`NQgr~fRjH$j}68?fy`>W5H> zQGeXWZWSY2t>P%oMz$V796c;5pT~LUN9c$ioXI(rU$V^Wayyn>K9LNfzky1B1HO37 zm~&3>UDZaiq`t`K^4HV^&B;pd+NItubEGU-6N)O$-pY>7<%_zbWVlc7t# z#%Xg(OU_+rs&kcB87fMvnxkDa48U#p$4R%)hNG>E+jorOszVJ(FvT3?p1C3omrpB1 z11gnms2PsxCp>yc&t)8KWmk=V=R4mi)H%%#kE`3-79_XYtt&T&(_dNxW@VA5v@{YY ze29VV(aScyLhAjT^|wgFqu0ur zXCaxB9O5DtSn)tzEYXHTN*BJSc8;gBw{JK3DE(lf!A9oWJ?TLlM~#ku>cIhGvZMBz z`5F=Wn!G)U{~$LeMEmU&CV~I0|KR0#*`EDHiF=!W+W5m(^0ucyll~d$(@@bWJ(E0C z=wbHtG|D?NY*(KDU_!g(v_d{nwNOmbvy&~v6AbRui;y*~)AlPzsSz<-qnEH5>pVc5 zUX7P6zp(X`^@vvEx7$vC`&QcpB4$U)S?P00Zx*{V(ibocsR<0nc<53h{ zdu5pdk$&Qrr5;Mp4Abe~#yRu97-u5B^8X1v^Z0Ql>McnlGF&8o&uj6ry=N9B?rVC+ zHM8E~F|Vlzmfs;#=vk8F)G;rdZ?CkOyoMPGav!5nEjIk8*k&~haT|nO+@vfZ`8cnY zGgA+>bjio~K*Z9eBb z9L=mtyy;zK^={Mquk#jMLW}=a~drip!+Z?r11VaX$zTGRI=&T zWxFVj*frE`NrgSS0L!d|s(&_uXPbb_6)wW9gvlSSIJ2taUx{Wye&nsMDpT5Gp1zhM zb1YaHpBB_6dgWz>3T0t;eE9~Ya05|R)jH?;nuC@i&EUX)d~ejQBtBiuw1$N_Gf~i1(pmcWAZSdFNRXG409pd6%ONd%Zu&hU;kk)*zwBF(y^hQ!-s6z^mm zJ>gOppS59sd0ACmb)iyGSSIgHXoJ%dreMrm)Y9jT+LUEgQIGK0z@qi8db2mIV5qHNcxW|P@ zqqA+KRC6-2P@1Ih(c0y~Si|yg?b5`CMZVr@cel5Hc3GT6r)jlLzqhlmqD*P`&+C_MsjHx1{Il#kfwoOOmhX^jtE^&5|@sKrZSf22szX zXXhw?O}1LaHi81*csVYRgh5PX9)h{D-imUD}ibdFg`n3uRxmy zGe8B8uG8>TEL6C6P#+xMu}Ga{dY8UJfqXOOWV^6iktxM^5(chkGIs^}p{3H>;82oB z9vK#_&O%b3u5s0viu?Nr(HhLlV*Lx9X0=v0x!96g+)`Gl3M+4HlgWgcsS;*%45%e)Xr6cPi%wkL^f+V-=pY7N0OD}9?`}L_49)JH8{w9n? zF99CyRxU=nc}BT*Lo?Hq9HXm;2TB;vF2fdkwXf?5oQs+_jUKJx5-^x)vN?RyBg<(5p zB~%kJTae@?M{4@;z^gAd6kqz?;^fbg+pf5~`Q1Nj`_t*(@;|&5zxkqdDegD_J1Jp) z^T&f5gZFXI`F&XYW!86Im|0A|#_?MRTj;J^Dv)vgPA+)>v0jtg^=uJ)mR_%aIW|rQ zVS7qVQjaOd$nay*AkpOsaWYionbql1&&DeAgl31Tf}B=q)5?GJBciq1hZ}5e_xd{P zu3d#HQ@M4(QqFjhtHW)ss4AmF zvOTk#JSe;f3229rqmTlgf95EE8?S^dsBLtSWz=X3XYC3)yo+mODW>C6-5|xR=tr>Y z_%-0B?@Do7A2%W7XC^^aVm>gv+1wiH9WbW<>6;ntbR@f%0Napww-6T|WU-e?9^DrT^F91L z0+U+nO<~d3c$5Z7vIx?nEMKOTo1OUvK_f*{VO01ir&0Krzr>duA18aCwbj+zH0&A< z1`#CtrzJ;RBQ-T6u6G=NjRBJ>(C84)!W@GkG~ym^?46bzcGFwj!>OL0)Uf*`Q?SwQ zXbhV0?6Bh*TM{C-!PzYDn3L<81=21Tn!1bR@{7@6B5y-3pV%yim_Ur?4J(#MdEPMQ zLm)@UsVqLh1p|CXiBsHBlC`82OP&-OY2eiG9qiOcAjL6oWWK*oh(? zKFcNN86Wg8E(C&Y?&&61knba|O6a8GE7h(z_sQm86QnkmYB&b8YYN0nOp4szVr;3x zsQ1N@vh4Kyo;|nR^3vQaH>r=- z9`Ezp-8FNpMuW{}FxZ3#ou^K>q-Tic;VsNP%Sv{Qre#f!+h%m@iVRkp9`EP=XCZ?9 z=7;-H@(%O;eB2Ha&}4J-@tup=eT>`}U}G|xnZ?eITV-?oC8lP`RpheROd0x^_rO+eelq+zCD2y_fEJ?f`l{cilqOXsCTr&N#%f1^7ssaJw+)FQ=`L4!Q zS6f@>()fFBOD`q2-$vJV1-^UVn0Hr#4Y^l0P}ao-8=ipUL~WtlS?pr64YOF9qn zS^nR?3C)c}RIym8^rxpbbWWeV&$+b{ zU9u^Eq{z2vCI^pM%pnEl%)R6}lr5DI;XFwu#<>@BDOJeo6}er-+$c%V!XX@VBb=s4{870R%gs0LsKe1^Ad&hO~4tZE8p!xl22Lg|kquaMxEA#RnQC<8x zqc3i=HTaC|9QPT>ZvIyT*7|8J&x^JK?t+tlrp(`FoS47O7s##_x71D-)3;T#^lda? zI_=v1QpYS)#mgY4fn{xTcYR z>&3NrI_I1v;#y2?9Wsg2%0%l=i6)!PrG!c1M`(@$9+fd+1(fG4gqv>3t%et57eyIt z$b2C?hvj55V($&}v80!FayucLuX4&8-M1!&7S$J;Lf}pob}KQz3@7J&n?NbZ(5~@qjnHPvk}cT)GgsUS#HjNl$$f~ z-{s~MD?+p)G+DCFsH8JamaH==CF@M`yk#1mM=OfwmQk9D>@akWi!zxyiD!P_=I(I* zx2ZkJVX=^YkzW}6Z*qN(%lRp0{uH1k^94D`XvA{3WJebtd(~197LUO3jElg3nb708 z*tVSY%E~r1a!+)g{Yp>Or)KV_mTU}vHctvYmAplc9bq3e;Cq>ECy9AmV#(s< zHhlVJm$By$39aO6;YpmwEM~b}%4EbjlW2kE1KI#QCo(>+BHOjxmxz)UPn;8rwi0p` zsdpKJ9($>#g4BcpdY{W)77(5+P!!asG!>dEv#d~7l1yT;O-|deURZ;FZMg9SIVMrA zx;p(k;l`F0TDw(9VxK&PoV=FvcSV?6T=*_Q+6ST)?wAEZlE3 z(4xVbJ=6AGfa7b2Ov!T6B>%@enVhMWNc#sWc)y+?3+7jqH4Yt3cUDYK*mY7W61;oZd=uf9vdSc9crn69R*T5oci3P_r(oT z)|xocC`x25e_Nx&W3xJ3QF*Dnm3XUz^(F2iV}*y1lOWp{e_-=e0kg9+l`pv5CPa4* z6dapU%Mq2D(kzAOFr>?Q;V7TjF**aAFAJ>t{O92Vbb^cg;h~J5CLYA`?B?Svf46-u z(l48H&q>YKY;!7qwVko_x?Xcts!&^^G?xvzoW^8TN)Vz2vW2c`=CM4ao$`i4FH{igB@NsD%&A>28oY^rWUtVOGE%WvMno=`&gOR*(dH;Nq*heP#ZHR<~LRa%=QLl$(+8H2Bm*q*0MaZq$0& zmQZy{yUM(mXR~P6PB#r{+u0_|7uvjY)1#Wb4Lf^0#bi%v{!0pKwxZM|V6H+TO8fPMfd&)P`7SN5{;;rWFl6bU#Fut-5J? zbY8Q=;SydRj$O89-nZ(5q0lDF=Jof@yRg20Cgfi8U0-FKXE5B+yT{WI5hW4?QKI)2 zb_pSRM08=5wOF0it?m~Iq6E>27MOTgrAy0IV5?!Umf^GU-(Ux!a`S)AxJ@sNV z;&(3MDKl-wpTB2|f(^1de9k4F%Y8AxHGJ0(7~&Z^@VgUwl3Gk89#!Ck0gc5t4Q^sd z`-wN~l%dR}51@gcCiQPxd?S^86)9Po(6ML_lxY{}_deqp)#4A?^^MNpS{_{MCoQS$ z%7LV2cVo;sN*zdwBP_nwBUvp_oW#y-{)}(GjjB(I`zM}`VJ5!#_%&YDtR4nWItDPN z6N7P~(C_pnetr$)Cl|M`_j-yGML7L9{Tk5+Mevn5^lM>T`dCTi--PkcEIRbLR{)Uh zD9x?^B>9$xmVmy@+VGWc`qeI1YP&;?ZUAJLZYwOf(#4~??+u^P4 zwC*)5T?h0xyZ%qySIQv&NAgp*m8LU<3>>=R4ewVJ2g`zx`^R*L_U?bC*LiY{g5f?p z9Uf;qbCvPkt_qTaA)kHd%3b$v0%H^b{M3P!QGZS+)>o-fSEEo33y=of$56U7FRpUP zsaTr@N(s#>$o$X~Qme(A(%S*HD9zEq8L!(@g%(H{7jWWWjP{dU#3Xcae@U34S_NZ_ z$npl};zD!uQ&8Rqo?0Jfef6AF+CSv5lt@$%fuBJF%D?b*Avyj<8&-uacuaV|Fo5R3JMQu9@zdK{t5p9?!xuI-UxK_S8e050zq5?| z-p|@)(xzZI>QD)T3H*SF+U}R%@FT}yR9LhJ>$Tk!)5uPWgngjN1XPvv@FA9>DF1Oo z`Vef99RpI@u($JeR7}XTuP#Mch`*f`nbjEw*`f5O8!$&?Q%S(iqAUXrT32Bic!jOC zf&_haAHb!R3r$besn05%%camP1_*RhIENVeB)+P)%Gpyps5Z6A__dX-{C-ESFITa$ zTh%^m-6=L4l=g5dxvv4HG1FI?z!suNjjl+3|5e`7!4v&8y5M?9ejvHSGGc%G$!z?= zjonm*3=aX-*O!2qF8i_naxLfn#NR)>GJP?wJTqp0J6w{7JsX;62eDHx;F4mMP0h`| zX8HD^=`sI`bC0 zdf*p|W;>G(T{Aj}SUY}uXP+^zYf{v<t3omP~ zlpn^n)5yZ#`-RPE61d#l3N$FGSvrMtRfr4Cncq`TDaJ67Jj{Cd#4rO5ff2?`qEE#% zlI9#KC;=XR(~X|2rWot;KkAWNKzkq0$P3n`KCtE& zY4G!5ka_*&#LQOkOYBKTa}7+>Uf`tH3X3ebY=dmzQNHNB`wRL1Y^vvnwj}8?BDu?K zrL^c@w6a0lwl4P$ZKF%@{FB+>?u)Z7zvdpVnp0LFXjRjoviJ0~^%T{0>RuLGvvzO_ z9CY~!4$Y-{U&&Tyt-OPugeeDTQSV(SHKxq5JlMm%u)i>ZZydiqT+?v7`Yw7%r+#P~ zbtr(RZb1i6!a}G;%5DDzKmrwDHx9^^4Z5l}M`j zj#D8J^RU3evPHo4)4&EH<$vT9@bTyetO>0{#g^|phFg@j{85`TbXN}|eM6C6Ky&Qh@N zUU8buni;A<4dw=uO--1VMZ*d+#QT-;w|G0dNu54A^#Uu8=tbOfi(2%xN{e7`Ig|fe z(Pap%I}5XkdANzTIm`4oCM+KYz&JX+LA}$dj+nKrOR4iVnuO_WiNedElFL@!9Xz=3 z5>P9-+=|=^`1jt){8-rhkglz36FdLJ03F`YE8+Ve?f+LFp=!B5vc$+Mu^=D}k2$(m zb(V5)be=Ga(|n4jHKVFf{Lc8^zhtE{qx=U_6qnLVvHwOf>F>ci8QRaU!fJKqGSHvn9n4G)vQf;?ECF_@Ks>vtF7Ak`Dbj0 zdp;cQ2GfK5)O-4ld~SgG@Tc4TJ^FlUjpvHf_gw<)KMqVbwT_OimFxK5+DWFWDJXP+ zR_PkCpEu^nB2@@0?4u9?hS}+HekpwQ@`l)SwYxxS&R zAdc?otN>$y&E4pvU4EUphUH} zdO)85q@P)gj75wjLYky^LqI+hZ`O#p#5Y9?;^~zk0i&R7Yrz&cS4m`#r zWND_WIW$xCY6u7m<1KD-+W9q={2WzZTdWPQV&vN@@ER8LvX4-JKGZIb#IZzypaV9d- z)4gyMlY5-|1kR$vmU*VRPEvq3dm1S2MoYtXa!hPD9}a9vv5Tl9!6{sHMXE-hUMJLD zGt~7_Yh~T0w}(T8SHCN1-^2<(*fl*57^hg#^;Es()rnKi`{uEfLTdNUdw!a9U3OR$ z#sjHVI92(9Xo&vz`X+C5fIwi;LTPyFtl|j!CFoJ6&}tA>>^ccOVlJljMO#8|x`C7stR5m)sC0P5nON3x`J9=7!n$xBbTw zh-{F(xJCm5lQ?3Bp}?qHh6H-LJJ_>pJ|^_gW~~TZcemqx6Uz3k6Li^~P#*uwpDW3w zI(EKKfFr3xXLbDk@5bH`;Y;m?2U?SC%k+!2D*-^Sfl0cnc%T$EO(^fPpf{~M3n`fv ze65)^IqG9F%Rp>I&!T)A;q6s9TGA1BG;d6E@c4dK>LkPAI(b&H#7KU1BmZA#RI`o` zgRuTv9rutQysj2{5kCe#=IVG4d^*+khKQgnwYio9mT1rc-cO}}Yfsw}^{i{bU^ z7gHcUMT}RMRW3KgrgVT3^;Ay$ITKexr`i`cKEHJql_I?nsc4^$<$wAc#%3U?#`}wd z0h*Uw=MPl%KCQYJiuNB`z7d1|78K}pJ36yr4VwI-?SQ9{hbwR_da#IhT^ z&XtMZOJjO}vUILAK$seKkYO)xaRs`th5@9&5(ax&V+S=xzS z+FJb<=@jmXqpzbyOc1AC@fn;=N`f3Ve${CH`@0U~7i|O6puY*6+nZ+>^E*k=q^3M% zmZ6c+j(Hy+&5PyAW8oLp-(8>x@tCl-rt!-(L)4ZmUsQLzv%SWr=6O;K4I1xvcSq(b zSi6<@7qV-&SRQ^0-oDKY4{f$z><@$imZkSYhR?K48-L`88_T7Yn<*gl zrv!gR!nHnZ%=}=NEb+7iWjoneN_Z)YiH#W*$RO{8zRgV4DKR)TFuOw-!2kGyw(#m8 z_D^e6T;aJG`Ct)lyOFoNL96wSK&TY?O?0eZOi?tOwppF3AbSDm4 zE_1!;;^a_6X2&US3t}Y(?Q6r%4WeGJd~=;Nne}UMdE~5tHx@{JQ$wv=3Th^^PsQ#H zu<@H_)%Osqv*tSpA&X1z|J3LB?n|8H_~jW(e{y7?N_i!CY$V@F2|sbsbNpzGeB!Mo zY%k-1Crd0jLE;V0|JNz(DZ&fjeLQZ&SAsfWdpVuVcO)~J2rXQL%_{!a90luLc-LZm_ziwuAlzg87q{t=Kw?ml5wrPbFZB*vH1n7gjdH|zGhC40Y`3EPR z3cXAv(z{o+V#;9n+po?B0F&!hn@SAQmA>Z`_500<&4yH%|D05Y{(v>s@?KBg3LHlIZ-#=?e!Qc-C zk+J3!my0Prn*6kk1ipC6O?IAE6|y)!-?s@{SLyFp&xL1rS@I(-8F$Ii*u(HI{sGE&qw;BUhB`f4#y%Z?vT*|ulTR9b|4E*6?J zqaxS|N=(7jzx7}2rCXJj6b?B?>8ET;bQjPh9pP5(@?V+cMoLWh&L!(c7v^@1o4cf` z%=3j4@jGU&0M;vox=9AKdYtFZ*$ej?=j0KubM#8eiQm>##8&ve?enmyZe$l#hwikD z8i>9ovn_eV!mZh`RCcJtH6(PIV<%>@y}K&N+y%AKKqo>*oJz@XrTPxgrul~`?>Bf< zl6dcw-vv}q%|rt-sZ*xs=)~paU*@*v)c^e;*$OWOB;dTefETXh0m>Al7c~k-nNDe2 z3Rp79Caumr;=x@&GSOrw{tWiWI#YOvBIH<j$LPMnqSlb6@~dWw#D3kmq$EujsZuFx&a68sd6fxE0#?F)h0N~nyB_3chm}7)xF~piMp?kfmR(KGl7TNyq1T3FD_1SR%=Ms7XzAdOWzIqrLJV!?fk&aS{UK3 z@2vq70e-a34;#hoTn_t^`K?uhpT1|T`WTnn>5FK$jb*Q7Xuq;CJAOscGdd+?9Hz?Bdrua%GD0!#C%un2_!ERS!Wwh-dD$R97$; zM5@R*81aVQQoifhvKup3MHZVWa!av_X0xyp6rjn}GC#C2Rl`lbj8cJY3nT_@?6y9_ zqew7{ThkN)<9GSXyS=4%cQSpf8D;(N0GsW!qosh!o?6Q;TH|CE0cjyw6lqb&MiE`5 zx4xCGYR&wi0cl8Yd-@SCbnXZ?E5gij*1KoUkkz)*40QS&`|S~+K6vARX|7hsJ0_nm z$X|?uLLiRy)kuQXHlCy2_Ti;7WoN{9H+E_8o6%M0R?Rb;hVX2brv;c>PTdqo1Aa2~ zC}3^0-U;rtX@qgjs6q4rdf+o6!pF?3(xTCQ&ApPMYS{t|Hn^^3rVZPW`O_84BO7)6 zlJ?BYXSLQbx!C<4BU5dPf~CpF8G@btL;nL%t7F5=EJd|5S@JaM3{*`^QEe;T2AuUtUIt??tc!p)qf8OXZ(rxz!N42+4@LBmF5^+0~EOB}QRh@Pg6?TZi}~{_e3nDjLhMb?nAesaz54W%LX8tci6sydAvLyFMqmB8o8}nz zU${N<)FIp8Vi#|t{F6@hrSPm)7M~W)F1l~Mb)L-rN6cLrQ_6cWch4$~e#^H2RpLi< z@GIjk^BDGBZf#j*44iNQP;6cuWKiD`lCmaFEAUxDqs7unZdlVMM%p<%@p=4OXV&oj zJsM|nyOKT9I-3`dwVA;3oELXQ^m7!Bn^&H-{Z_#T_e-HD1Z!<94$r-)!4uC7Fhm{4$8n7N1Bm#%IRzT<1hU2|iTnL}JgtAc=%N pDzKoKm=yTg|GOs&2LHdDxR_Lezyrnm*T%%6V)r;Xm9yHWJVffl*nPCVpyAX!V8f?JZ!BFr- zGaDtECf%(>(q_|cr6}F1{ZqBu{wS+f70aZ`L|IkppLSJk8mW<@?4NX_sK2u9rm7bD zyyspUGi(@L&N=Tr=iK*s-j8#5Cp14fJrcX3+Cpdev1wf4yX&vmMn`SY`P_b?ROT^= z7HrXl!olu?{f)u_Pw0Y)-BKCv54ft2Zx!;z-1zQ8zN$cwjKz5>6JN7MmmcjEI5yiV z*s@t$p_HfnX^+Zxrm+#H4^GE6*O_h7)lmT|;qs|3QH@FojLAm+$Xx>JdAL(i$*-G6e=;TlhM275YN z?Yu8C9(h6QakLUyG7Fu3BK?o_OV-Bx47&G4k6ABJ)(Mn-_G8xiJ|0LsHE0=uW30Z4 z)YZ#LkbN;8r}o+%_1Z00Q0=)k zHz)lvG=4XgzB?Waj^9mFJG`^5+)8%utmjH(B-X>2DFgjg_Q4b80-$bTOAC6kV9$!}WKv$PK@%rIyhhMKf(8Q~nY)7o9W{aw2|^?wKa$w6_+kSH zunH;~!J>?jLmxpC4N`EzRYxeZ# z_PSuO&Mq}*afki%oyus-U+urr8%+6n!4CP!Q}FBs%HKI=VfaZ1USSu0!k~8;`diUj z@y3pR8~SbNTY(yOsYXgOG1Xi{u89ODow^XHYZKI&u&e`QQTUlyvk1Rt$n*#bwMc(c4>?%oXF9A44Xj!3{Q|EJp1 z6C7JjW!5G_+iTWVYh&)We7+xF8*2|GIJD?I`&62cv(RDu2~01;|H+3MfXw`U#dF$8 z^>$r#1i8o_gcv~p^zBf$MYw+(Y^SoJ3xF_7Pz52f5v^GHOd0&aOxmqPpDk^CzI);<>*Bc#(e{rR5 zY1OLyefoF*X!J)zb!(e-nSac@@%lCC!;r=H^~cSYP{{VT|85P1>aBnL?WX!r$ohjH zHiiK8>=bcr0$w-!=5NGXNAT)u@HUd5u|{x-04L3G8jM^b;Dpszp%M+v0Pmg(6Ov}sMglm1rr(eGtnBZy}E=@aRzr(ct%>}Ehay(xY9 z^fl=pEFrj403glsd(gInEj)pX%kVNfd)g_{2xGJ(zM5+y$4rt9i9H4o-P^* z06{N&t_=r7pZqhN3~%WtLo4E$vZxQ-_@JG;8vW!jR*X)dkB?cQf5mEM(%M{O6T?XQ zSwYFPlV)`4QADBFEAW`HW1DbK3Cr6ABaM*R1jc4)(1FKGSRIu0p2?CI^5WmAxB2*_ z6B*Gll2*o?Q6$1!ugX6={nu_@n+8)#HS@`NB0*+DXa6gGguEBPvGM1}OaTK7j{+7f z_`Ze4=u>{DgAb_^79a`batkDbH5T*|Qg00x=eZAyh>Jd&(Wi6K2rh!cClCwFD;V%% zN8QSO==lW~lqzxN;9?=tB21o@QyS&LdYAA3x?ULcm|9FmqLk*8`QYee;Q7*QI2r1n zaWT)IPt@E zekkLbg|BezNcjr;D=lJ-PBl#0W z_zVtDIw|Qq{A`~A6f1Q2HR8n%uwO@l1OpyCJ@|eTzTE^C9J+sCMAyMe#57%q7{e*f zZ&&9L^Ms6#LxqkaGP@2{f_vyt3BG>CXcvKj+XG#^EW;8(Zga==8y8(7-kuqY%p`n& z_{QV8FNZzd=JmS^vu%-11jR=I|LBtXwb$f7?G1i9C*9lrV%`d9G7Fx4BDVowC+nw- zFaT@~z+@Jf27r=Sc90Z(icV_vJI=-1vYV{vu8D&t5;T!njX0<$LA`Eg98$0@L9Pcp zi?DMOdbljW&J9=>5_TrP@B#=2K^mQ zZ{29mS7)N9Zvr1aB?z{&O)!2N<|Miq5-spZ2lPvFqaR_TGH!pSS=NI%50OloW1Z3` ztjT0LJC!HpY}oMt_kYn3$?lx~nwkikAU!=F{=e?Gf+_OkhH;~U~b;+I`W z@Tb_=Upo1{*3tiF4W^Ii&A*s_a9wZT`xVxnT4y(FTW#6f3R{a zoxOI(P z^3j<0h^-tR(w>XU0sqnC!$a>Oa2Vrb_VgKn#GVz583HhYJ;21&vGjNzo1qE#y(9?u z1AgeaGKp_DL}nM4r=Y2SWrX39GRzi1zx^x>FZhr(%74b3$P7pmu*Wbvfi>}m^{{k8 z?n9mLqcg!$c-M<#oiXb$`##=0W<|EZK1bIf5}hCdaG^sCFr5Lo;idXVrlv-*ST5|m z$Q4_3`T0U|YrD)7=@{xbC_2sMc2JpmX<>SH`R4G%c5c61*tbP*9Bfe8E0e~OiQJyC zD4D_{y_7{uCkqD~`^CNTE*4OqR*b~eG&a7U+d81n&6IQZiyJpeTlWhzq*ddhJT?+b z#%OYq$6^_kXOb$aWb}Hvc)t+mR9{)Bsc6NhUR5b+jpq&uH1)FD6El;Gj}Cx!rnI>$ z%4v%a_V(@ zJeB5}mgJh6;pv3R6PXw%nW`qZrl>rX!Z@vPElJ}PTFl2>Eva!e9$N#Z#RuzUQT&5$ zq%_eN*P)*C$H`WxFP?K-i=E1J73`H_la{HeHAS)aOsNP$Dh0#MVky6G6f5~UP?v0| zMdpheWn&~{8#}o@*!Nk|IKNC3Wam`fnOGdOL2`lIY?kK>o7nDFZcleA!SP6i*Ac8b zpCOP!Bdmz&DsAlM3kQ2S6x?zplu4x_g&mjlyi~oKQ pd5j9#NDd3TyJb!WK!36LDtsWW=K$nv!B$dHleSQ3>h`ql{{imN!xaDk literal 0 HcmV?d00001 diff --git a/pitfall/restructure/stream.rkt b/pitfall/restructure/stream.rkt index db7f7ac5..f012b23b 100644 --- a/pitfall/restructure/stream.rkt +++ b/pitfall/restructure/stream.rkt @@ -80,6 +80,9 @@ https://github.com/mbutterick/restructure/blob/master/src/DecodeStream.coffee (set-port-position! _port current-position) bs) + (define/public-final (readUInt8) + (read 1)) + (define/public-final (read count) (unless (index? count) (raise-argument-error 'DecodeStream:read "positive integer" count))