From c8a5b047bd150b92049db2bb1c242a7d8b89304e Mon Sep 17 00:00:00 2001 From: crc Date: Fri, 4 Jun 2021 18:34:59 +0000 Subject: [PATCH] image: rename s:index-of, s:index-of-string, a:index-of, a:index-of-string FossilOrigin-Name: 88416f7a177a6171739a75db5ad4d399735ecd29836424897629ca1787d776d2 --- RELEASE-NOTES | 8 + doc/book/tech-notes/underscores-in-names | 2 +- doc/book/techniques/arrays | 4 +- doc/book/techniques/lexical-scope | 13 +- doc/book/techniques/strings | 8 +- doc/words.tsv | 12 +- example/Atua-WWW.retro | 2 +- example/Casket-HTTP.retro | 4 +- example/advent-of-code-2020-day-5.retro | 2 +- example/dictionary-stats.retro | 2 +- example/muri-with-hex.retro | 4 +- example/retro-stats.retro | 2 +- example/string-to-number-with-base.retro | 2 +- image/retro.forth | 22 +- ngaImage | Bin 38784 -> 38756 bytes package/extensions/deprecated.retro | 5 + vm/nga-c-native-x86/image.c | 955 ++++++++++--------- vm/nga-c/image.c | 1094 +++++++++++----------- 18 files changed, 1083 insertions(+), 1058 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index e05866b..2560ac1 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -28,6 +28,10 @@ - `s:contains/char?` replaces `s:contains-char?` - `s:contains/string?` replaces `s:contains-string?` - `a:contains/string?` replaces `a:contains-string?` +- `a:index` replaces `a:index-of` +- `a:index/string` replaces `a:index-of-string` +- `s:index/char` replaces `s:index-of` +- `s:index/string` replaces `s:index-of-string` ## Deprecated @@ -36,6 +40,10 @@ - `s:contains-char?` - `s:contains-string?` - `a:contains-string?` +- `a:index-of` +- `a:index-of-string` +- `s:index-of` +- `s:index-of-string` ## Hooks diff --git a/doc/book/tech-notes/underscores-in-names b/doc/book/tech-notes/underscores-in-names index 6b430a5..535011f 100644 --- a/doc/book/tech-notes/underscores-in-names +++ b/doc/book/tech-notes/underscores-in-names @@ -30,7 +30,7 @@ will allow for this. ~~~ {{ :fields @Dictionary , (link) , (xt) , (class) ; - :invalid-name? dup ASCII:SPACE s:contains-char? ; + :invalid-name? dup ASCII:SPACE s:contains/char? ; :rewrite [ ASCII:SPACE [ $_ ] case ] s:map ; :entry here &call dip !Dictionary ; [ [ fields invalid-name? &rewrite if s, (name) ] entry ] diff --git a/doc/book/techniques/arrays b/doc/book/techniques/arrays index 1d44526..c073cd4 100644 --- a/doc/book/techniques/arrays +++ b/doc/book/techniques/arrays @@ -88,13 +88,13 @@ and return a new value. ## Search -RETRO provides `a:contains?` and `a:contains-string?` +RETRO provides `a:contains?` and `a:contains/string?` to search an array for a value (either a number or string) and return either TRUE or FALSE. ``` #100 { #1 #2 #3 } a:contains? -'test { 'abc 'def 'test 'ghi } a:contains-string? +'test { 'abc 'def 'test 'ghi } a:contains/string? ``` ## Implementation diff --git a/doc/book/techniques/lexical-scope b/doc/book/techniques/lexical-scope index 0c192cb..fd20104 100644 --- a/doc/book/techniques/lexical-scope +++ b/doc/book/techniques/lexical-scope @@ -29,11 +29,10 @@ out the `---reveal---`. ``` {{ :a #3 ; - : b a dup * ; + :b a dup * ; }} ``` - ## Notes This only affects word visibility within the scoped area. As an @@ -52,5 +51,11 @@ example: In this, after `}}` closes the area, the `:a #2 ;` is hidden and the `s:evaluate` will find the `:a #1 ;` when `b` is run. -If you have a `---reveal---` with no definitions following, you -will experience memory corruption. +## A Word of Warning + +Use of these words can result in a corrupt dictionary and system +crashes. Specifically, use of `---reveal---` with an empty private +or public section will result in dictionary corruption. + +If you don't need private words, don't put them in a scope. And if +you don't need public words, don't include the `---reveal---`. diff --git a/doc/book/techniques/strings b/doc/book/techniques/strings index d4e59bb..d21b19a 100644 --- a/doc/book/techniques/strings +++ b/doc/book/techniques/strings @@ -52,10 +52,10 @@ this automatically. RETRO provides four words for searching within a string. -* `s:contains-char?` -* `s:contains-string?` -* `s:index-of` -* `s:index-of-string` +* `s:contains/char?` +* `s:contains/string?` +* `s:index/char` +* `s:index/string` ## Comparisons diff --git a/doc/words.tsv b/doc/words.tsv index 516cbae..309e710 100644 --- a/doc/words.tsv +++ b/doc/words.tsv @@ -88,8 +88,10 @@ a:fetch an-n - - Fetch the value stored at the specified index in the specified a:filter aq-b - - For each item in the initial array, run the specified quote. If the quote returns `TRUE`, copy the item into a new array. If `FALSE`, discard it. Returns a pointer to the new array. class:word {n/a} {n/a} a all a:for-each aq- - - Execute the quote once for each item in the array. class:word {n/a} {n/a} a all a:from-string s-a - - Create a new array with the characters in the source string. class:word {n/a} {n/a} a all -a:index-of an-n - - Return the location of the first instance of the specified value in the array. class:word {n/a} {n/a} a all -a:index-of-string as-n - - Return the location of the first instance of the specified string in the array. class:word {n/a} {n/a} a all +a:index-of an-n - - Deprecated. Use `a:index` instead. Return the location of the first instance of the specified value in the array. class:word {n/a} {n/a} a all +a:index-of-string as-n - - Deprecated. Use `a:index/string` instead. Return the location of the first instance of the specified string in the array. class:word {n/a} {n/a} a all +a:index an-n - - Return the location of the first instance of the specified value in the array. class:word {n/a} {n/a} a all +a:index/string as-n - - Return the location of the first instance of the specified string in the array. class:word {n/a} {n/a} a all a:left an-a - - Return a new array containing the first `n` values from the source array. class:word {n/a} {n/a} a all a:length a-n - - Return the length of a array. class:word {n/a} {n/a} a all a:make q-a - - Execute quote. Return a new array containing the values the quote leaves on the stack. This is identical to doing `a:counted-results a:reverse` class:word {n/a} {n/a} a all @@ -400,8 +402,10 @@ s:format ...s-s - - Construct a new string using the template passed and items f s:get -s - - Read input from standard in (via `c:get`) until a CR or LF is encountered. Returns a string. class:word {n/a} {n/a} all rre s:get-word -s - - Read input from standard in (via `c:get`) until a whitespace is encountered. Returns a string. class:word {n/a} {n/a} all rre s:hash s-n - - Calculate a hash value for a string. This uses the djb2 algorithm. class:word {n/a} {n/a} s all -s:index-of sc-n - - Return the location of the first instance of the specified character in the string. class:word {n/a} {n/a} s all -s:index-of-string ss-n - - Return the location of the first instance of the specified substring (s2) in the string (s1). Returns -1 if not found. class:word {n/a} {n/a} s all +s:index-of sc-n - - Deprecated. Use `s:index/char` instead. Return the location of the first instance of the specified character in the string. class:word {n/a} {n/a} s all +s:index-of-string ss-n - - Derpecated. Use `s:index/string` instead. Return the location of the first instance of the specified substring (s2) in the string (s1). Returns -1 if not found. class:word {n/a} {n/a} s all +s:index/char sc-n - - Return the location of the first instance of the specified character in the string. class:word {n/a} {n/a} s all +s:index/string ss-n - - Return the location of the first instance of the specified substring (s2) in the string (s1). Returns -1 if not found. class:word {n/a} {n/a} s all s:keep s-s - - Store a string into the heap and return a pointer to the start of it. class:word {n/a} {n/a} s all s:left sn-s - - Return a new string containing the first `n` characters from the source string. class:word {n/a} {n/a} s all s:length s-n - - Return the number of characters in a string, excluding the NULL terminator. class:word {n/a} {n/a} s all diff --git a/example/Atua-WWW.retro b/example/Atua-WWW.retro index f033bf2..9ca0083 100755 --- a/example/Atua-WWW.retro +++ b/example/Atua-WWW.retro @@ -111,7 +111,7 @@ These are just simple accessor words to aid in overall readability. ~~~ :get-mime-type (s-s) - [ $. s:index-of ] sip + + [ $. s:index/char ] sip + (textual_files) '.md [ 'text/markdown ] s:case '.htm [ 'text/html ] s:case diff --git a/example/Casket-HTTP.retro b/example/Casket-HTTP.retro index a4318bd..d87624b 100755 --- a/example/Casket-HTTP.retro +++ b/example/Casket-HTTP.retro @@ -96,10 +96,10 @@ a look at the extension, and mapping this to a MIME type. ~~~ :filename-w/o-path WEBROOT s:length &Host s:length + filename + - [ $/ s:index-of ] sip + ; + [ $/ s:index/char ] sip + ; :get-mime-type (-s) - filename-w/o-path [ $. s:index-of ] sip + + filename-w/o-path [ $. s:index/char ] sip + (fsp) '.fsp [ 'application/fsp ] s:case (textual_files) diff --git a/example/advent-of-code-2020-day-5.retro b/example/advent-of-code-2020-day-5.retro index 68827d3..9e96b09 100644 --- a/example/advent-of-code-2020-day-5.retro +++ b/example/advent-of-code-2020-day-5.retro @@ -86,7 +86,7 @@ work with other bases. '0123456789ABCDEF 'DIGITS s:const 'Number var 'Mod var - :convert (c-) &DIGITS swap s:index-of + :convert (c-) &DIGITS swap s:index/char @Number @Base * + !Number ; :check-sign (s-s) dup fetch $- eq? [ #-1 !Mod n:inc ] [ #1 !Mod ] choose ; diff --git a/example/dictionary-stats.retro b/example/dictionary-stats.retro index efb3328..aa3d766 100644 --- a/example/dictionary-stats.retro +++ b/example/dictionary-stats.retro @@ -18,7 +18,7 @@ Determine the average length of a word name. And without the namespaces... ~~~ -#0 #0 [ d:name dup $: s:index-of n:inc + s:length + [ n:inc ] dip ] d:for-each swap / +#0 #0 [ d:name dup $: s:index/char n:inc + s:length + [ n:inc ] dip ] d:for-each swap / 'Average_name_without_namespace:_%n\n s:format s:put ~~~ diff --git a/example/muri-with-hex.retro b/example/muri-with-hex.retro index bfbb68f..8945044 100644 --- a/example/muri-with-hex.retro +++ b/example/muri-with-hex.retro @@ -105,7 +105,7 @@ conversion. ~~~ '0123456789ABCDEF 'DIGITS s:const 'Number var -:convert (c-) &DIGITS swap s:index-of @Number #16 * + !Number ; +:convert (c-) &DIGITS swap s:index/char @Number #16 * + !Number ; :check-sign (s-ns) dup fetch $- eq? [ #-1 swap n:inc ] [ #1 swap ] choose ; :s:to-hex-number (s-n) #0 !Number check-sign [ convert ] s:for-each @Number * ; @@ -118,7 +118,7 @@ hex conversion above. ~~~ :decode (s-n) dup &Instructions a:contains/string? - [ &Instructions swap a:index-of-string ] + [ &Instructions swap a:index/string ] [ s:to-hex-number ] choose ; ~~~ diff --git a/example/retro-stats.retro b/example/retro-stats.retro index 3c187c7..22282fb 100644 --- a/example/retro-stats.retro +++ b/example/retro-stats.retro @@ -59,7 +59,7 @@ Determine the average length of a word name. And without the sigils... ~~~ - #0 #0 [ d:name dup $: s:index-of n:inc + s:length + [ n:inc ] dip ] d:for-each swap / + #0 #0 [ d:name dup $: s:index/ n:inc + s:length + [ n:inc ] dip ] d:for-each swap / '__Average_name_without_namespace:_%n\n s:format s:put ~~~ diff --git a/example/string-to-number-with-base.retro b/example/string-to-number-with-base.retro index 6d1d392..c109318 100644 --- a/example/string-to-number-with-base.retro +++ b/example/string-to-number-with-base.retro @@ -39,7 +39,7 @@ here is: {{ 'Number var 'Mod var - :convert (c-) &DIGITS swap s:index-of @Number @Base * + !Number ; + :convert (c-) &DIGITS swap s:index/char @Number @Base * + !Number ; :check-sign (s-s) dup fetch $- eq? [ #-1 !Mod n:inc ] [ #1 !Mod ] choose ; ---reveal--- :s:to-number-with-base (s-n) diff --git a/image/retro.forth b/image/retro.forth index f044a4f..2e242b8 100644 --- a/image/retro.forth +++ b/image/retro.forth @@ -878,12 +878,12 @@ a key part of building the other high-level string operations. ] call drop-pair ; ~~~ -Building on `s:for-each`, I am able to implement `s:index-of`, which +Building on `s:for-each`, I am able to implement `s:index/char`, which finds the first instance of a character in a string. In higher level code: - :s:index-of (sc-n) + :s:index/char (sc-n) swap [ repeat fetch-next 0; swap @@ -896,7 +896,7 @@ In higher level code: [ drop #-1 ] if ; ~~~ -:s:index-of (sc-n) +:s:index/char (sc-n) swap [ repeat \duliadsw `1 \fezr.... \swpupudu @@ -911,7 +911,7 @@ In higher level code: given character is in a string. ~~~ -:s:contains/char? (sc-f) s:index-of #-1 -eq? ; +:s:contains/char? (sc-f) s:index/char #-1 -eq? ; ~~~ Hash (using DJB2) @@ -965,7 +965,7 @@ a given substring is in a string. :location rot rot [ [ swap [ over n:zero? and ] dip swap [ nip dup ] if ] dip ] dip ; :setup s:empty !Str #0 rot rot &s:length &s:hash bi s:empty buffer:set [ over s:length ] dip swap ; ---reveal--- - :s:index-of-string (ss-n) + :s:index/string (ss-n) over [ [ setup [ check location ] times ] buffer:preserve drop-pair drop ] dip - #2 - #-1 n:max ; }} @@ -1169,10 +1169,10 @@ located. ~~~ :s:split/char (sc-ss) - dup-pair s:index-of nip dup-pair s:left &+ dip ; + dup-pair s:index/char nip dup-pair s:left &+ dip ; :s:split/string (ss-ss) - dup-pair s:index-of-string n:inc nip dup-pair s:left &+ dip ; + dup-pair s:index/string n:inc nip dup-pair s:left &+ dip ; :s:replace (sss-s) over s:length here store @@ -1537,8 +1537,8 @@ and return a new value. &swap dip a:for-each ; ~~~ -`a:index-of` and `a:index-of-string` build on these to return -the offset of a value in the array, or -1 if the value wasn't +`a:index` and `a:index/string` build on these to return the +offset of a value in the array, or -1 if the value wasn't found. Specifically: @@ -1557,9 +1557,9 @@ overall. #-1 swap #0 [ TRUE eq? [ over #-1 eq? [ nip dup ] if ] if n:inc ] a:reduce drop ; ---reveal--- - :a:index-of (an-n) + :a:index (an-n) &Heap [ &eq? curry a:map identify ] v:preserve ; - :a:index-of-string (as-n) + :a:index/string (as-n) &Heap [ &s:eq? curry a:map identify ] v:preserve ; }} ~~~ diff --git a/ngaImage b/ngaImage index 6aa64657fc21c5f0bbc10814b8dbe7eddab2dd4c..a7cd10ae434eaade6c81771f321c02b9a5d8c144 100644 GIT binary patch delta 8003 zcmai34OCRuwVsPy!XTpz!(|w!!!V9Il6iC>BQ=H~A}XR17!j4=4~V8wAp(kjh=~76 zP;p07F+M}o*BGM}U8c{ZP1Q7M%<_-6);=4JCXH2}W<8qdOY(|&-@cqfC#;84Mo{G#E~y{khFl5T#@sFO3@CUk!(0-to34YI`d! zlr-E;=St#?p$3D2BVMPu!`Ub0APUf`(aO-|=NtILNf}{R6|kbn13p$(n?o7c;Ot2rjH2BwSBsVZWZK3x2OY8K;jHb-u&- zkSANn6d_B5Y=D$?rymo>e%K{)u8qxMV6m4@Lk4245r+y-pW}j%JQop z!S)3;XSs_mL*o+Wqw)6qhA~19U{g!GEa9tQE+&V2WzIe5YDicpLiBP!hdqi+qlRiJ zSZ~hyZ;}V<2quvS1t=6esJ7>0t{6&Y;Vqycn%A z+NsLifF!InVSYY zmnw3Kwf;RkMZooREhkH@fkrfNT&-ybG>+N;`7Sk#_s}25y=pootOp^#g!OlQ9tg{I z$Uzo5GVXC&HQ^to!IrLY3uF~-%Dw1V2#q%om&3!v3hEt{z_d_z}`;-t$$9Es9 zz;{2|lb@yzis1p83*6fSkxD9=0)AyAWd{6e9vr>&gs%i5)oDPXI=TejT)GC{Vlq$k zt83tSj2iOXR6a3M-3HW$%mEKy7=}GSeW^9yO_wHys|SIi^sWjbl@nwt@GEC1v%s%j zgu?=dhh8lRS3d@dVPqV_Iq}V z%Hwoxl3)1=nG1bN7G>f)kE-xpOs$1J^{0qfLzfGus0*RBP|D;f>Skz1sA;m_wFVlm zL<>u7x&|~p$$7b3VLL-NCugf~LAyc?Q!F%M%G2supu0e2wtLX@0|QYX#&)q zb4r%^2sGZnRwU%ycPTK{5)sV^R%a{?9~7(Eg>!`Hv=c$8v}FP_8cP?Z^`jNjPns%_n z5arayTA?G-PPeBGDAXqa>yQI0vy;(e$Baj_9sU5Md`5y<`MG0z8{arw`Ti z{^2<%4yMWQEP=;PM~ma=#`I84Rwfy9!Ds}-vVCSG#myLC-X)ShiH^9lRLY&c}z6sXh-|3uVsosav2Opqg18a|<;2WUw1L?t8Pws|TUIPo1-T zPaS~9WBUUn-}yP`d?DY0P0r4F=yH7A&*yP;WO^*EDC64qlzD9b*CTN$6as|D)g{kk5eCLuN-O@0Qz?xz#a zds3OfQ@$T;Y&gASeqiEz3fpx*h9RFMz2J`{^IT_AK1brz+9e|8;3lvg5quM7+eqLU zG<~i=j4Q6~rw{ebx%u^aYRuLq5aa-(k&J`uaV@c&EsjMlrGXQJzg=_?;1W?M7a%)t z621n+GIt+i@MPYpD1r0(`xz$c$~X})15zgWnXoBXBRMxbQaKm=mc$+NoN-JU_`gDH zrnYnsB`;4<@W3Gz~2GD#%f8RUfnSV@yT4#}*BZ2gY^CH#i$?sdTtJ4eUGRb~O<=hl~|& zTm?xL)-bNS)UICzB^5(*Dn*J8(P@al{e{dCa$eAL*c@Ri5ic6~!1c$kRd^M(2I@sJ zEyz&*Ot}l}=05<-O@A8tZCbX#rxC`?`wr8qkNsnKzNTL<@Y=$Dgb~4f9vP*3r=UycIPf>fN z2TuXtRN8IB1)q;F=2xTfmddB3D!VeC4p&>1=~N1RD%Dk4jq^kWM*YEd4z^0NJs1?kxGH@5Yz0-% zv-)>xUFdW5b#&FDziDC~BLx06uLrP79Sbcn;h>lylncC(h~Ebf~qak1AiNo3UDS&*?B zm@{sK+(%W5y~<(Qv)HNqJc!5s7T~w39sYgPx!9{71HM8@OET&^p!F3eW+~T+@!a8P z$iG5{!X|6}l1Tn}cpP-F&Bn0)dr7(yPl-$Iij_t$ zb%vPZX-i!{TLdWF)fLd?K6?l~nRYGps{`Q8ruL;Xl}VJc%%e>ZY+2Y7!1JhL*?46s zom}SAUg+U30&b+vWd+J^3M_ZqUK0M`Q??GaH>hd3SNSEKT<&x=0?R=k5q#NSEAR)X z$4XJPaoV5Qi*3Ml%UgIdrPo>$gL8Z&a>!%vSHO4Ccw$N^voe_u*Y-C4uVB4Fr)%Ag zFM?utcH}Yo7uX|6Sy7PWc8VoJ7GA=5#?a*>L~sQ*YFJ^>G#Mcl^$~KV(!mu&O%d?$ zhzCPv(ft)3}WY~xG;i@*FU+#MeovyR?3GT7dNe|0@ ztmYzsXwOO?ja?b1?4{C`Zrjg95~j(dew61oPXA7vO!1Tf!Zc!0szaTuknvg5@z zca>YQP}M4{79t{L&JN^EqCKm;>Ogp&rt_=3<|JtHc9jBsJQ*9j(QL)O(IEat)d0yQ^eB{f0gVrJvsf^$Wm@eQ!)KUx6uZ=}+`hLqJ7Z56!o?#X*% zIb&+Cwb*K)ajs%Wd9`s*|4xOg-Bi*PN~gAk(u)=0nTMEZz}*0iBjglc5fk|W{PHS! zjk(~+9ZtY!^o*lQUA((9FEYc>^((}`%JxBzY)65wQ`H(zZZ@_IUuW_GkVl{&V1xRo<&NOg>I~k z(UOsY=N-2pos|g2NHVVTsZT)*Q2IKrjX81y@zb%)Hj5h8;dck{xaN7(w$7?NM|JDn zNJ)^Q@y1Ch!I7{@zF`Pv~+YFr<@;X=qe2AJhXPe%E z7V^FLtv?X|iyra2fiID(u|Pcq?G`O-%t*b*9ArvBx zG27vC|1**qPvZ4P-#eJbeiV3dD1N)!^rGGI81vxQe{hGaMR(i_SMw7({o>HVOQJ9N z;>9=w434@bd@8bV)L_W5X#6w%1hjlK`56iOMB&S!hS3(BKx@?;SeDbBCa00(c&ro2 zyv3qc18t_nEzVTkj=uOkll}bRr~hs~n0y7wBX%|LUaH&T)MR7~B4u?4scnnJ(KA*a z+WQfEf^KfH1Xa_y#X9;Z?C+s9qo46y06srd1J}oM!&jxu`7YwFb1apvwo>KR!P7Sb z$+h?bI-b)EO0*in(JDq776uHt96q*v1}S&H#Bl3pI`j6z&*M7}X`lyN)6@sh`cmq) zp{hE-U~o{?HoqDJEs+jx^Q!%!4JTK#h3;)jR(}jM0m!e8fL5&A%bN$N&j6L{==J6y z^}~VqjA&$uJ`bV?mJ@*a{NS@l-j_BA?rKQ5y7^oq*S}Kakf$EoR=^f~7h5PeJafnq zp$~96j4d>0yL;d(>_!-WxQt?8PTvgqb2MJ47s$LVCJN3L;cSIGM(x|3CTV#SmUpRh zySv-+OIXfP61g?zaBBHK#`l1)(j0i~;=SS=EZk{3 zg+HN(-%p({SydanW68E7O&t!ckcxIVhfNa^DC~O~r?MSA&KCaq9{v()+hGZN2HwR3 zsn3FVy1gUHSSW&4k+RciUJfKzmH!dlL@7Jn1Gh2<$@GR^%f+7_n zr`>pr`QSCt>75pBu|O_Jo&?VFI^Egn)>?%}zVGb>{)k*JdyIR9XDkI?c1H34$>k~` G*zo^Ozxn6@ delta 7889 zcmai33s{upww@pPh*3ru$DeT+VHigmkZ`0?+(t-*ig*J=QWV5dw@FHh7Xk@^yd;Vj zTxgow&QhPUi;<_=wzJ)3r|F4`W1XzF+jzQovhA+i?QNc|dEWK&eLN#i`#JMGKWn{f zy=#5zTi^Fz`Re(Qh9e;s?G}@%Bf(@kiQ{~mr7((qj*2?EH0sVlA`+&`qiwg>_R)4x z%4m-x#bh!q!La}b|3Yza{2{7@cTc3r1YqjTRve7kdxV}F?KB^j==any+G#z?C>)VE znDZ80A8qgVI;>`yVI%aGs`;tJF-GT-GCH=y;Uq`RE4w?vst{c)@VH5Z5aMZy+CfxB#jbZBnL z$bx%?qCh%f_eIg+xoJrnrvzjf#u7CYfMUe~Xw)(Y%2-OtPK*cX7aUCH(V28p0?Np; zi#y<%O~qNs3wkClll&MkqFIMzopTrx-CQOy=Vw39L9I#!+fd+mSy&-(eH8UAcMgEX zh=5n1$Et;oQtaK+>y3$lYt#t)rlXA9{ z^^mIO7ototM$s|Y9crTNTno}kvSd5O8_>?6zkcl`1+x8N?*jidik{yQzsj! zXTAsrS8#>evz;lIgRSV{Nr^8)7a?JxeGth*eF=MC(#MR{eONM%9|Eb)fPoYkvV7Mh=uA@oI_xDreajSf#CzK5nwItt87h zr?#Au#`(l7_@AWGaX#&jv>Db{=;?8O?O8fE&ZQreu^(HyVjlr+Cu@#J`_kZkP6atm z?Y|A~2R*od0{)5i=lHb$rH&lC^`FwO)+vmx=D2iIzpmb{M1PH@V0Jc28Sm09(!+eN z`+pGcp}_cT%TLhQG60M;Y8&tGw%i8G6#8-eJUvZD^LfSGJAv<`^4wX`o*tf=zzzLy zMT({$a&Hq=fUV@7P;1!*0A~p^W4K*q^1!DS2Wqw3q3fDIU=V?G3s##iRX!ta*O% z4zQE53S6`>FG~CuP`H8i=0%9}KxPBI2lO3KZv$Nex&qY4K)2;bh+h3orUq6MD5GD9dmJ~dQ421}%2d2edCI1CikHQv++@iLGV z$ZJkTkNEdCWfc0g52>=yFV4Z+pS|>9VYs*mq<4*37^Phy%QU}+il+I6Rmc7?JiDev zi8vsKf!>=IA(DY&c=YW>5!y(y6#29PGhI1gK2x;j03=n-gqk`F*K&ifr>$c~^B*v39^;-hKwtsFdoukvBU?A75S02(c;>-lqmtrbx|*08cq+UrX@9X_f4fIX3*l)t z;;t1B*VBN43tk2MxZ#~KGf_X=Ben(J7Y*-IGvoE1lRXIUyN36NnZxwHJu<%n{5iGE za#H@RcySx(Uo+hy3&wLQQ#`eIhN_zJe(bZOQ^ErLdsxWvDJ6RET$CqXUZ=dkc% zUS^4os7~7LCQ}w7o%B`7V6!oAw0#0uOYP=y@bMx{rPNZpK7~s;f~I<32E&>D$>Z>OXt1^--DmH>i(mOrzY{uGnqTdJ&m< z+&0|Ocq7%p-e$xem_1BymaH4Nud{bQ@SouI>TS})4EDSVd7cu=ri)Y1E>L5cC+Tm@ zfiE5hb6Ee5Z5XdsZpSZxf1&oW?=U3JMTkR^W)6lP+;Cj?8M#kyxKK-bDrICf@4tw zKh9z%-I15+$9X<+7GB%Yg!!HjVa6lQqcnMeQxLR+M=KV1Lfm_xCdYI=-A+SvJ`VLu zfPFZ%E%ch1!QDPcoeS-{fiR+a`nwI@iDW5vr4%p^bv%l!*qq(9OlCVG_^!+|%LXo^ z;&Q)H--Fares8^z6+PGpUkErno(*|8t^v0~mhuaUSoUssjA^Pdz(g5P2C0(lmNpIRU^Ib?LLsURe4_Bc2j#%?!9R|ph1xQ_ z^uvAe8Xj>Lc^oHX9)57@g_Yv`ZLoFH8z#)a?(XLby1Y4r5sbhjFTdxk-bCkVA( zL%^CqqQVoB=A_lx(P2EFxlUuxmsAXQSIW$nWi7oV_DDH_+A3`N0*U6xH-rM&ldr&Ie)peAP0a$rxifb;7nz+MI^1ff|?Fg&($7N?qm^ zd!dCIo?TSA%&r}#re&^M4{!`-)w7aUna$(EH*g?rSr+4XF^H;~*$mrh(w6&T&q(iY zWKcS=YTf%ZdAU9Iiyn;DAjaoLvE0JH)4t`t`l#5hp^eu@G^UTl$GQ2yVG{FbINgjg zPji0g*C9da9-T2}(Y*nfbCtO;stXa@{vmBx;66t11sLLE@dO`3OIIWc9b=}_z7-_A z(28ip%4GMwTn7f5!xA}CA+5LusF{~g<4UJvCVMfOamIti-pQ~nr7pz z85!CgS^X<9TtO=(R3*n2Nw4wJgUri;IcpQ-0jj7<)}E)`RWALhARhbo0RMs7;XgoE ztCGc0U_3=WkXe5jS|nf5kS&0NXLXUIA-{$Ug-y-sOSS{6S16u&XONBYpMir{fiXh5 zSK%~pSX|d>I3HK<3lC((x`4aK2l;p4NAgt_iSW=}?b7;DpxWu~BY9_$L+!*X&{Ji; z05$f;D@S#>NPuNLwO5yEMU+zG)hEkHRk27d8d_Ru{cr9ZfH+9zbJO z56~W`($$`r-7*n}sGHb2*j`iQN!ls8zS`?}^H+$6U^`10^&agn6sWg5K9iiDRbAq$ zZtDCulBqV!2f#PzRDF7qJHBg1#>EaZ>I2O8C!VExUglokLMaVS%}Kcp9<4uBG}!fC zGE(KdjGRMhcSEwc6`l+_)sSo*3QgVVZihaJL}Ql~yT#~y7OW+d)tK4c#e7(n(B{T$ zZ3}fY+A=l(8{a)lT^~XDsgrxZ7ItnSZ#cEmjj*YEE>~Sk?uYD-Dp+|wC6MYQ<58ZV zf`>do-;k`ewyYz}HQ{Rl4vta1Ju5r71b#KzA?AXk_H!%nsUA7ClELJtjmToEsq5p$ z|ChF%xj||F1NiHB8eJbvi`PVH8J=PA9^~=?sV{Yl`0|m(NF`EKVhp{D=4tuqphcob#^V6+8(y+4{`)@sr^(2yp#0x z$=$gg`!~5BkWu&eNNIv)+3e)--A6B`Jaj>Cm zVQmWi&qe)HuM=`rQgIzQ8O57oBTn_sqkPlDS;}G{`F2-Q?9vB}0AXSPZPCA~ImTtgF>0+_ptDV#C$+#YqP85%ThKy+KA4yhNp&GBrGLZL-IHFX>NW?ReM%*^+axM^MM6oVY{}Jg~;gp-17R z$=EvRp4&rlJECb)bG)WgMYA)uFO!kR_yiAGi%6asSCK&nn@6U8A_r9Obc{n}>PylW zfh-*5gUln#X1mCRR!m8oe<$*xHB$R#mpcy{7gh|ZcAk1Ct%0qDEL&V!9;Ixt$M)o^ zD{2#XhbXYc6)+g6xW9a3;jv%fEEpjd2mkoBuV*H8#eN3d*Cc;J7yV{Fb#Ae{UjgH^ zWKH~4mSd~a{0Mce$s32hi{-j*zqppB*D+p@(7XoVzN{2~Y1T*_z} zDT<&ir<#_W`mxaXyx-0e<8ZH776S7%fvd4$B#`l1Jw#&ZquccpA8qa^c~ZN%ow9g-1FI`8_p~zu))J)RKGyT_n&6x;s|j zAEjX-T6iZ+9C!?p1Ft~ZDWNsf_*ZHomAAU?9tti`hwmxeMb)VxY)9@i>1TVe|90sg zoj{Lmiq`I+&Q`mKhcSO!)Gp$+=uDw9WHAlkXj!84{$5#J3R?InS)5