pax_global_header00006660000000000000000000000064151144126210014507gustar00rootroot0000000000000052 comment=2f30a81bb2beecc24693ea3a6624ea02f7ee9475 replace-in-file-main/000077500000000000000000000000001511441262100147315ustar00rootroot00000000000000replace-in-file-main/.c8rc000066400000000000000000000002551511441262100155730ustar00rootroot00000000000000{ "exclude": [ "node_modules", "**/*.spec.js", "src/helpers/handlers.js" ], "reporter": ["lcov", "text", "html"], "sourceMap": false, "cache": false } replace-in-file-main/.editorconfig000066400000000000000000000006021511441262100174040ustar00rootroot00000000000000# This is the root file root = true # All files [*] charset = utf-8 end_of_line = lf indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true # JS [{*.js}] quote_type = single curly_bracket_next_line = false spaces_around_operators = true space_after_control_statements = true space_after_anonymous_functions = false spaces_in_brackets = false replace-in-file-main/.gitattributes000066400000000000000000000001271511441262100176240ustar00rootroot00000000000000# Set the default behavior, in case people don't have core.autocrlf set. * text eol=lf replace-in-file-main/.gitignore000066400000000000000000000000621511441262100167170ustar00rootroot00000000000000.DS_Store .nyc_output node_modules coverage *.log replace-in-file-main/.yarn/000077500000000000000000000000001511441262100157605ustar00rootroot00000000000000replace-in-file-main/.yarn/install-state.gz000066400000000000000000004025321511441262100211140ustar00rootroot00000000000000ҮKd76'%ܭ2R @H)ɽMUmG Gs&{R|]_j{7SzN??ǟo~?>ǟr#ϞT)cGT̽zl7=}$ԭV;%M'\&Uբ~殸?~??_w??7~m?ebsCwYjEmCFnYtTwnLݲLvN[x5͝{trs⪖ͷ/kosֻ߮d^WvW kuPI|N=wݥFk٩AY-9%h۷o}hmyaxT1g>i;'L~rM= [^XyQ'RR >F.eG*wf{5Eu ͧرNXɫ5ƛ|Kk.߹؅߰#C{QgC[դC$zVv_WS]5eON ؾfD_&Fs=EcKWLo)y^VU|y^u}}*NjtG"QQ^ݤb횉c]\5೾Srb8^NiWmݺ8L3y+ٓ{]J}TnNiNg 394Hwf6u Ҋ<ënS[>mkMrL8w&l QoNfa=yqSwI#g$^RܬMsъqzSf64wDc,wg=RΉڪLz1:9/ukJ:TLO[_?GVY}+8w}\#SMaGϵwDngS&ZNM)VisҖ=sMN~]*첰Uk޳^UX卵T/qH("zuV>ժGTR{z殭gln?=%.<7 #U!ͱLKZJmI6D墥}(Pyͺ,'>CL;Xrw=sWѺWnL,fH3'9sV~yLdl|{T:zmS'ql}{\{fuZzŚ7' SeO}"+_wnr]}G]ϥk.~lΡ>Usc_Q,s]ʋDb/џ}dž?W9WW/(? 7ǬQKpRkbsXw>%s|ի{xestc˖x%Y'u.3v>FKsͥDd-N ~*Wz[$n\Eo1|i#0QlKpzwcZ!~GES.3)a-xd<eu.Nfzw[ab'G_F̼GJVu5e)&mzہOolߟiSKYk{[&x#\^Jm]][Dv9.niNmc?ӗb3ksQM5ݰ&KO癧|i\VB@xK'rnk/{szgkivr{b'+^YOBǟ ~j䬵K3{y8-i.r}&:_*]u:[tj[+6s}9w]\κoq;/Gs/* !K;;ڣq='TpŚjkf[Tv, \ݴZdcDOE/yLv uc 'i5'l)`\ԼA׻7 ~g!>oN"Hノ{r}~ ƹ{ (Tq3jwuUܴwv 1nyxlE{];2W^h*dzLn$Y${T/tȓuݝꜯsئ '~[Zt5-VK☟+)BS S]IcVĚFak]ґ%{ptxYˬmk/lj}O쮣=ꄙW& Y+y-EmњYde/(`W]tUYIm{*Ym=_K0)e`8uyZk@jгGMlJ]%l\s6ʕ7J{7G90l7X˚vfz xY~R 26ᆬsç,^^km[rWh_{oZlVڡEUEιR: G@Ove=o%9O; }s=}FJrulUC{ 7j{kA޵ҫI)+.'oe{>+)q^tĤwu|G("!6J>06I~pݲAs:.}U@ԒǗ'_-|g"Z(F>zXgsMFʩB%*fg*n2{bt;{x\|uzM}Q8XMn9_B u^|-q J),nTfͦѣr)G|x--n;ɍ>q\鼎 Tl׸5khˠSd}Jq#g E3$4}O'8{d屴Ok5ҲGnW㹇^3"k^D:]<-=8s[n3_Sn(M6nfgo]"lx{tL6jì PnF~-]՗k2/:u{X4 8}mܣlӖ]>!m/vd(&Mf\E]XY ;h;&tĶTv `Q8}+$~u#X,v%mھ,vuKJ>h4ڲ^m =nZIsp]*|1'E~K@PB_ٴel jӒ ={U ykEx]e֯ N{VwQxx ySм4(5Q^p]Wbg8;L=M֔ku|9eΒ7笲[5Xs_P ONnB`Z5'#FlB#zW%=B`y8!,=;/yrfzǽ;9OoWV )t(~T6ArK;k'n\Q:tf^w y%x쾗ɹϞ+xoһz qI"oߩdZ6䷬E/UACgF0? Kh?YʚU=h :Jʹj\42+d@Ctgd: '1kP~J:²x/TؖB_z st+nwZ]Ydy'2{NoH3دz6+>q~O/߿J$~%BT6vhS{Le/zLI-%&F*.wz$:&^Eu宽V<ۻmJCϽ׻te ث%vTow|Mݭ͇3d5v}oyCQ$jZBfo^dy~F^rs7߽(YqJKx6@zN{'g1٣z9pd/O%楳bI}pb%=?L4~es.Y&1>tDN|ąj6rMyNt \]pM/qj.ڜmpfFo:m%ykL!7h%f[EG{tQm{r{ 291Ym)= Gy_""ԧ^Wxe;:yҫ]O?sŹҀ5u̎W>OZۮk -^5Hgk -kp>&$h͒[m9?ts lyҵ>P3тfv?o6Ru)Ff5hByFn5_O.ۗVrzt, \x)U_|+2y}n{ān]N_cLb|ዊ4†EA4;@H[Y[@Ih>>K:;Z/mg0q@IR~~D]sIsߒD֯ײ -CylM@{A,WH` _7j `EF ]aƄ^4A4sgy=%׃&I)r:ٽFQEKŲM _յmpڇ=DyzxwT쯟[B,-zN [ce[e64{AREP 'PYǾ5Y}^M8{.rY# ĹX%fhmu*Rb},#Ź`xލLɢP+J[޷j ݀|)~J\K^Y/N_|S/{H0̾8i,]Kw:N =stHt_li%tLJ$[X(\T-_KlL#!ߋG7Hl=yo'cfjk`R&=OE2& d]7}o|馮)J)PZ ƦuhYXjdS{咔Zx헯J?  (Zz2$K3MXausn[ gˍ k4eA B,A4:2W//'2E( A]oP],-tioS׳^km|JvHg# u!'726[]v|Zb|S!&[lk/gM}?hdތAV'b`J_x) ԻqB\:Ӑ׳ͨKV`Õm<cAزH.ܺG'{cp~h{O<7=Pʆ}ɳ>i y.x)M?uLWB肋#m!`m>G/H6NYt&!<3P $mT,ZoZq_?Ö*G10>G@oMcdv_ g#^BVxm bCO#=ko}V~^3J Yю}[s`K8ʙL|>Nl1_Wܟ-}㙪Zi&QMn: KY ʝ>aRH;\/yna" @ ] ֻg<תZu8w `!>@c }lo#RY}6PUbi5p/d'tCuJBℯ} ˰}`rSUȽSA<"v9Lz>,YC(뷬g/~~ w5 mw 6>~·uG/2@o1b]QɃG=@e0mgQuޏᥐ ,k27e!-h(^+a;lꪊ~}kz$ٽ8fs(] FIu?DhDi'bGs{Yck}d8v`Mˁ_368x &XN|xU: {Fӟ *=A^C91yݶ626Xw[\d$flG>ć]!7,hi=lpB?ֻn${lh!$\Df6=fA,̮>tZ$p|_!w۳HTŶ۶㦇s7_')L z7r:X1ȥu$t-wA4MvZׅ,'7<*,B3*|vDLr4R8@a|@"}QH 8R@R\s7LߝX< `kK.586jFz#淈_~LBuFHƍs rl0B0A2G]6HH o%P4woDGm['0C~y?.baEK_ S@^QW=@GEx "Mn;48ŖG2Ћ؃5 LFy*ťmē3}qV T/ K`?2>)G"$EAg3|rQv)?`bQh-X7>tEwpa˔p[S"Cj<_Uv:O4l8.@I g`kv 4@Y D=Ro>'ޡՅZ@9+R޻na'Ȟߍ'6}"aWhՋr ,sV7* [|p՞Hf7[^ȱ;dB@>\E@pVN|Za1];ZaNV?z5@"' 2 oZQX.}tglqg RvlBuaz3F'J$&6Lh9C2+M\>\Ӳ3 I1w5Zp> qrTcϳ5;~#i/邟E'LZm=G>L>> WS=QPr }7Ha?DR _A= [v0@qaM &J47uF|.Pk/{!dAl/1ׅAB;:jWQ`!,Q [,x"^sg 7h9ܲ%í#k,lY7J4~Cɀf:<#Rb8 #Fh!O_~yA&/xK}``hq ߪhOޠɱ ݁ T|=EeErpY_hZ kj%%\ޱ; #$9' j$ݘNv0Pu>?|(6M ;;|O=[ކ67g#8Ɖc{-^FLY'aF:!wnw]":5lM:b;t9yZhD߀a Os2# ccm} :a[4 `~(`f`P~B>;$0 6تנS暰agdP!~Ѿ…`QZ[W{ļ#DZ\T>*"cmi-4s!}H9R {0B=;ؒߑ& cv\+Bc0]btHy Ma0"exNAg{٧(/6]}p#+B}ro[w~'kzR NNbQ՗]F\aZV<=r!/7H| 20Ǒ`"#-'ϻX T#U n HJKro/n MMpua t:I%>HdNO4^Ku"jDH1_R>aZzA.!nHz'1kgaNYgFT8t12)0G!$Lژ@D˅mzI FZ"Ɓ9FCBRg x#ɨ8nÑLQ{CL݉Y+͚bqbVh G8A#s0j$vjV*ZS4SwA{w0 &)D弇e; Bl/ X?P8g?& i M&bqa+>axbc+NHV y]yi)RRFZR E/C#:?G]7_-OW?}-6ĈEf']nU汛AF(1O^286&Z]EA5T74IPP3+׉2$vHRMrz ewaP4}2[%})^;C9 BBνECj+A%9.$;os3:p>S C"%!Lo[IS,dA'0U '1 %b.z ɢqQԋ~H*PhQ C|&P{q`*솼74d g7 G+yӡ}ƘmCg,o|x.dڵf2KBA4*| Òd M dC1OnS&A_C]A b)t>6y{SzSaC|׺3KO9+XB_a ['`+,OM4I>着3e%a :y[ƔE{Vf\g .6>XpW` q sbz!vň2歪$ƫg[kԸT2mRO=H?(L MWOHJũ 8қԙ_Bu9^zQNm|j*`UH>s!UvE+3E 4TW~}` Y{vwB]ZOj-!WiHJc䓮"BԵd6? = iCg|tVe+0{d LZ(lB9 9UHE0b&/=c0E*`Su=zk$y-dm'=q6ٙ[Pԭ`Nsp4(GA7T&K$_dJyC yJ~~^Uk] @%0=gFNפ36@-s9KeyjqCeW-F\ܬ(L[3jEيIpR# YkOx0g&q7޷19FULea3_?jS%w ޤ` wڄI|*p XC4O"_=Ւ.TTQWy9CV/PqA$"8q^7q5[*- `rDz^PdkF{F^jI~+C\\bg9$`Ew6P3f>J]Y'fs{4吽 rډ9=q yTR } ύ_j>42X+9,%+7[gi :B D~ZVl;Jy1-!k[-K1{!rp|o%<9d:q3<.+oCsoGz;##P$Uٚ7txi %%mwz"(0Tيl! )o3b1˅^4cF"-pHJeUr|uF_ଶ7{ Eo$ oa\w9$Q K3FSTnsu$8=gY!)YlaO0vj_?VjAkt҃aMҪ]fٔd3HW+GyO,j)WbbpӐOT e+\ t0ݤ:XHsNkE:MxÛ:k͖5͌:< -jL.bW ֙嶜=nx/\SؒB#!j$g n"%c)eh&)dǯw3@ɫ,^G lf}d< f`Д64x2nU%v_ KCM{K=E ¯q:ACA ؏k[V&@)S%ɚȭ33~r̄\ݸ̉ي~ɔeY>9gU¯g/|_ߟ~?}~o>>~w^?o@xO)əT1}l@ޭG&1kd :uM=/k=) "c㊯-cUgrFhjW԰m$ kZږWwk2,]#!lQkhBBvmnL-߫w Mgju(tלtJ /]IѐmLVVF ]kF!ߝ26)4p%C޲Seޣ?3xΩ*=S&RY@Hy$5N}$.EkZb,eδ24λN#_ TO R  jdQw^1ٕ*:Hz35]/ĽZVbIg79qK mDPgi'rG%Xw8% $)Z(hfS~a9mȑNp1Ddõe=Z զ6; 4_J0'h`nCTw$7 -/: )W^YZ$3-KCw!FOgZ &>ǖՇH*Ǭ E.wi]nuڰsR./F:gLzeesZr!"mE-Ngj`V;JjJU VaMv9zn+Ad)7HN 3Der|Su%G[#h96XpNϪɴMPYpk+ea hh$uj oiHώq;=^Hil)5q95K^ԛVj{%-tvG }+>g25uVildxlس5Cf%V*NIAZR6A#];ڣ%{;OGغ1raV2d] kd _ ^]%΄%i͕T۝ 96 CRQ,>i.UG8{ᷱInfvO.kUڪH+˝JDvأ亊Uj'tn,sh<,HlV(UU=sؼFÞ}eF=B-׋E\k2YAҳ(jX^{lȝð^:4T]QIRpHMm8BW_|,~YhM__Oأ re٦ZY8a ?Bl:(1X7\ TPd:W H?BQ @m+Q b,ݮW75=j=e [%qO9ӕbS1 8P*dАWieL:Dx> O laLl4\D3M a\h կ^d>֛^7{/dOD hg[Qvy6iyz^$b#Ղ_y3vlOXVI2!(O^44@,l͸)9)wUƤX]!^uE=?Vkz *:JcXQZzM@kg8-qR/Eוq ~J/.:@;4p- +&d&ʀ5IZk%SfH( ^ pL0VV; иf޺Ë!I U8`D`GcޠmyuL%]PCe;[NZkq)[c[C)ҥj~{O꩸͘Ψn#}Oe?985/` V3>T9 r#L{WzFy BpuY]aݩm4Kb6(\oΖG#CC-w"*ْlڈJv~}u8dQ#0Eyع;gq W+"dhxLj `Wde};Irt,[ lo4r#)+[D߳Urk3,v X-yW2;հzw#̀O/=)tgfzԸ 4Եj!l֕ƌ9R(tjo,kxvʑa= fa@i"D|HNT|2g@⍊ʏ-̶C|'LON{a\j^m sǢ$STIG<1miw` EVpuꃽ$ptc6weE0Ns$ 1We71ny^h&Z4ә0OGi9T:V+iY٧S[(uOeQ73W1 ` gMM8u4דYPsrP{B09v!d?>o!rԣnϭ>x(mAJH4 pCWI<!yʙc+ U\30fV~MHHbϙx\xޓPf?(.2:sFUC Duvg}Z*VJn+V48x>Xձ -e3>X=p]L<լqNoLPTsӽG=@N ڶ, lºo:c086crTJvewmJ loZZl,}RĎni44ɳPOF3F< 9_DVdI즆&6"Ќ$78Zsݒ6IQl4/f-кSNPk?3k;As w$"E's_Wp=ZdVlW6iC<=EU ^bW*/r)+)uP$]f)cEZi3hKûeL\tQ[:a>g"] q1H\,ًԾ>, :CBٶ6ypLz„8SF?1fkG h=,݋Mך3!$mn:J|2)1KE`+o-::4lb^t3 Ò|Z7)ܽmıF'@bOON C|ʻir](4pckWZm qnREEbKkf:c *dwK&g(~4ik`7ZhC={FS7fy@)V'? ODɟ@.~'P|? DO~@:'P?? OP~='0? '0> |O F}I0'|> lO |)@0'<> dOK|X @<'= $|O{@HN'= TlO`S{!8͞@Kf'= L\O z(Jb'pC= MO YzOV¡'p= <=Oy[oYڙ'0< -O`yPe:'0< Ox2q??Q,Wa/?~߽Oati-i 68jb+fq*3uǡr羷{s6|ߵHTA/xJ3%>RL` 91uڐ*|q@INk\zMꞓ u1gc-/eG`_V?7NިzmFs1ʵ(/y6) B9J )<5 Ϣ> `Qf7tVEd )TZ%źS qʯ0դ=^#-$hORjlerµdqɐ%+e)b*(>Nh%j4yK}J]zM:Ӛ\<.:?kO'0|__7-0mv>sšI`3Nu`d|pQH=/Y램 X99/=&kacNj^&}*<߽;?r7>~{~`~:dt(hu*dd@&W_`.ՌIeW_TݷNe<"рˬT2cxwFx!p>eFCdFu19C-ؒ0qJUjOw~~w_o}xOۿb_˽vTxzi6*#p%Vhx.]NNtʜPoU@Z#1t>G, Rmtk{<DWTAJER\8Ť29"pZJ"`/Nhgi=pg;|__CA&9ڒ66)=*}>6r͘Rٿ/["֩`"WdZbDFʭ{.sx3ì(;tjKA#!o9Fptjk3Z!h9&3JدZDM|֗緳}?> ‹]J"QŎo9GWxOzsH_LmAzF1c 09hng#6A&MqkZ~OW^mVˉTTMG\fޔ6){B4jE{?-o}~qQt3mRM8*G\v HȰ1jZJ D:mc>%` g_&BNex;JZF-|CUD#EIk)kr&;cm 52!rV+V![e>׾o|EuqHD},k' a֩%hAE<6bmt1#<0`x=4zG_Y>>ihҮNiiB}agH?16:KB jW*cTJz*3o_ۃe{'jJPPP:V7_hbG_\-NDO9⦽7N|Ոtf #=nU@'Jv5PınC~P$Qo4eIt@IBAk3Ƞ3/nko7x?_ohlI%@ݸlDPQ^Vyܩh  _ y?%zZ|gE&k%Z4sE=ZRi؉4h.٘;h8߮ Vj.R@su|v ߾C|-}K|a>R G&I*T)P&f^q,maMZ:Y%͑p&=]%tքyꙔD@qNĝ%/qX"]q^ gEP pysdܞmH&{޽o}~ǭK.gzO#2q9m:Y?J@Jvd/'I:vK֢x D׊fz 3 Tl ]lE NO\=AP) Sj)DnFc |;8~ǝ_|?|sӧ?}{1E/2S̈́rɒ Dh.YN{mg mH% $́%> oeEH? e{z=5˔1OYXz $-PwPajs+Rii%/42l@6d}1^wMv(t Iq\*q/0`TxP( W5Zxut8jWD\40g݄p"T 4%k:EsډmX!ʙRO. YEhwVl57=u^;I{+;Zmz$х35t&7ylriGDx4f=ٙv2n7:ޭtj>qmTv$0+ST *Rh[VRFP+Lv:2V|9A ~]V86K v.Ç闎H~}ٙ2Ҍsw5,6B#Tj>Pbbo'c(^H+u si?Kiݾ4;/@o^+@a2/.fg>&'x9FEL\OIT,ЩBşrR@%wJ/]v[c<Ox~xmWqFAi%kǁFp 4LV(46x.6a rJ]L֋&zzy_T „ZȟC1RQ6&ʹEdɗI9.)$g6MptikR?]_iO(~ZD%V.vQĭh ȼR$K !iIW$ <u' %vH88l1 |=$\d2ueLS6lgTBe99p23k-?}ޯ|oy[ƖPIUKJK >;> wU .uNp/a:_2%oT)>8޴ N>7Fo} ~k9rU@9Eި]C,RVnšAHujUa4&$:KdZټۮZ dͽ;=6 $׌8gf-08J*rdY@li _v7b.w/ܗחL q7u_=2 Z1lojrnn\ߐ0`'}[pN9H~u>sի |hs:%h\ThәTaP2/4ݰ,G|m V8K;Xȏq:?~ֻHo}iʱ0^d|EQtsߐH8Y- 60~*Ao2Nc`>Djݑ _I [r`+T7fg{(*@}Xii.G`EMكNt $XīAg>1v<G/i},3TsXC# C[ק U!7 Ikn OE`rqD_䄟FN>hIA`_-GFErRe*€ cbB@&#ZY. p{nOZ">ܟVP]c>0c[asct[*t)U`#bxGҮבj&S% Z2;9įΙ!㵜д{|+7 W<֙RB'#)dViӦ4sb;ʌ  (d%=z'$˂q̛ӃǛrc_;y+[Y_D}-Uglu02}\jL nQn ڇf 띹h۝ڶdz}@Q,ײ;@/ նjG BFJuZmI) 0Nc /p1U${}<:??~|uׁr+m{T ƭH3rdr2bɸv6xtJM@<٣8ý *8ǻDQpn?`} zP9vX>%78nDTY̶:DqqWy#QwYjS榷6+׹Rgx?h?տxw?=׷~_x0wA9.Mv=j[? ǭ1N՗Lwm k}&wa%8xxbz'q 1/Z愉Ʃ?0hc:qAJ7E[MnXdfqo!N^QlNKR1_G{s_Cl9R Rڨ Ѩ23 & #k0M~9 1&l\`YWPGPɱyZP#U%NWs؈sfl(@}.^6@2;}S=v.~zZ^wx.9,ٞ^4%}sV4¤ AAqǢ[;΂&+ua0F*=[ c2sx;W\emP řHZH2x7Wo}~~SoDϘ5x|jQвF.]ʼ 궁'F(_,ͶR}wAgt^~xKnI聏2cRі̑]i SS[ %k;JO)q[ O2uw)jT;_ħ?kto}\ԁ6]]>r1ww wfuIǎ։mp㎢Z ZBB. g AICzj6g(:!17-e2;ͣ'7w#dL%M )'e[*F@QNۋ>%s1,ic>Y}m'eC5~^AjMYgk=EKoZ 9}3235aq}.`Re`@jY 2k#mcc ƴm\*Ǔ37 +pn93c|Q,? 9"qz3Jcr}džᅨ^RジH9G;8:Eԕf6ĒSnz]~Gx=Z 8vh@Cm EO0֗˨~!TZniNϥ֪;Z;i\8?y kGIw-=cv!.3訳7! Ҳ9/GJ;87,d`2*dOcoqKliwPDx&v :_ k[uNe{\Y2iHȧ%Ya dy˩zDP=qMޟ|KO`wTcŒ m,Q<IWW|wO/s~,1ڿ"魯/M{s6S9}faCqlzUW ^yWiʎN & h[13܇Xb)?Q[_WFM/[ 8r%U2go^ 5jZ9R mP1ށ{MsF(q;K_$;yt1#i8=r?Z=Uz֙a@7uihWz0g;ay+Xf?tϾymoqSƬiw*lW`aYF]Q);; `NESRF-UAABؚ12VD'萢F;;ctW?RptF5pBi}uq) 1vjlUЦe&MᅭjT07lw߿KU43?5$V੔sklO;r:'r6*gp3R 5R\4OoQ$۝f9] }]7'Gl]LSHjå98VNG˿kpПNjCV5<:Bpfj_͛ ɔ'é,j{Q\I9Y^ZΞ[ Ywl +>5QVuq's&M%DŽ!<_{ &k1BI( C~K>ë7xtS{li,,=1@ij&XQj.'Y!gTiU`g$ڏRO/ݗ6/#܌Y_q+Uf@ys.co&9`'eSwt#`ѷƸq;wA3߯ӚMQ1\e[ 5"LFDW8/W3s I:D&x^q/#U$4᥉ o_c5$[~QgA*N(BC$[`_*vs%IJ/IӉo1[H;@2P eӭez2J9,w!|s:4q}|[_AxpJ-ACYKQ2: LO}dw|J(o랃B/:g$ֶW.u?5 0'_;تSbm~sC=h9sY)3ٳ'тv`CTn"5v_x_=} *W˪yjGGZO]9em -}fvN&j:fٵ(`Qt}\%30]|7Yg[Ī4gu܊nQP \J=*͢C{ZS 79$K&lY|qCo} S?WHcrZpScjȌð{iV";ŕky+o ꉾ gׂ@u*:%Kp4=ֵ?b++ǏuWFPi泚 oV v=3 q׶o}?͕Ҙ hW; % e~Zfs$ZcÞLB'S1!|`Eg[.3y?.WWUxdJϯFxnQ5D-xȻKCN_ {茽,jeMn3Ҫ`Z(rbQvz|V_o}~)`'QR7{We+ d2c[K/iZWpW;7uo3irg^ȕz, {DfFDfƙJDdɞQP"`/j}V , ɪzu C8X@jrͿS^eVz0_kVgf%:Ql‚HRq6Ѝp lvW# O܍ayMyqn+zu$D,)&^mtI: N15D Hik7ϑ@vw^nxMuTb8"0u ( 6m]&vu|O(=W6zt?ݏcțλ`%vزc;v|'޼ "=rq+EOt*isZa׶wז|:>h4蛚G.cՎ gogq YmlTm 8f6fx^\z`W+#pe)iXW|7*j 9؄x&80!7mW??.&?yn,JO@󫒉4vr3n w4KCғ15@wPSj,KZ(_ f-A`28'(J 2*q<#5_Zrq Df9,DHÔWJ2;^%{< 3 l2A3 `Q< : rbq*m$P#1O&3`Nq- z3ɤ淟EB;jaj|f|B0ʤ V %+Z gYaܬԜx =|lKנ]ufUz Z0?q@w]n o2hfp]N,(|@֨X5m$DMpE syMp\/ϸ >Ŧ5-F;ϴ 5 ;3]U㖈0mQ˖ց;:u=P!\ɇ?MW~DeV{IX]&vKpfj;;lmtY l+i+uEV *=o &G}o`7ҁ!#Ezv΋d2! 5zYMyUe>np #G !.eh(w2J Em!d:@"p'"ⷃYv VX9vF>T)ϱf|41Z\ 8"laNdOV31莿cϮ4vVzۏû?/M YqgfGņV e_똞3.~kA ssc<2/:džV-\oz>_r}} 3eCEN9@TNy" .4+"HxQ9sDuw/=7d<?y-o`WV0|ӣ.ƥNu~;L< I32An$0@D@<6vqk.xz5 GN.Q+v5rdڄ܇BsŁP[!C{NC]bwta!:v΀Ulp]<$i=w^{y3b4#E{~1-=p.oQJ tnc.h$b2k~[b%>{߳/ #Liu*SxP[hkLN4SRb)kL$3(?qmno?Ps| UP F  0ԡ$A 齈\m ĵh@Ba̹RI~ q8AgĞ1Zdڂ$^XYäjadj;6(Y[v9ֽ;~%.S90+2F,Yo&RR`\1ˮ rK恝Mpcӓ)Co|BxF{GCF*pib`NʍgAf|%s='wP%#:C 2S<"<.A|g;<w V`tac6ؙ\C6# u֊#6fQ12#r垾&GC/o?/]oko?:<{!_Չb8@+AΠ%$S7ה 2gC̋%2y[B 3X8}eB̲S{%'TR04D hĘ9}4%x_y*lO֏&iIr[on|-Alq<6(mgɺxdx 3mi"nGAe&M[AgQ7kb/V6a)F@wβb c5ɶ4~M.@6Ss뜕1})OZ8"M }j˚~qͬէӬ|c` IՔaٍhWf:l G|/gk¸5ځW4tf}f8.H@yky +ր!y@*p*suCOtC;pfv^h[+k4@B,D'w< N$xHz[M@0#6M,vomР(p@lOҗo?^ۓug2'}_|#G0es6ƈwuWNKVRsoNccjv{SY)TgbQԶ;݉DWgS"@< Oۆ0ܷmDhƎg_ww^_}|= .mc e$j 19 $NZWG(KcZ Bmfg:w^5HZv_Fhc:Eᡜtf.w@*:;;WMG `TEǺm{66 oz~z7=?yo۠8BF*}y hݮm#R){uVd5ч+L>BJc>LSE/BӆAR@*~i/}.hZ[ ci` @po֫XfsPE<"`h+2v&O6~w^ \ i# Ycq$:WOXHVNIU&(@ܙ"$*]Dz+|!-n'$Wl^B-r~YPŻ^:bc-~`j1N%9ZP#{t^uƕ6F-çOo>d/Ż<XMHgit ?qCijt:*n`؂k agA&L%iSs& &`F@ )U-n\?VQ ȾO(.6R~s@_φ J O'6>[UʷKؗ҃7W6.aS}\)̅d̳!(40Ď?eЬw_B+q8e⅂8Ea2V-Nb94}p460'?7hA81s'ڤTjJQ>֘t`Np C$LN_??󇏠<>{_1' #3@&AWPsޔtc1WwkNb8fcZÁL;uEpx7jh>@8lbd[g Oݶ?idx Bt't]7G/3o1W0O^걯-"1`0S4>zPl|{P5kȂm%zqeo9Rx nh6R@'q]!cox-`5jlѝ>+@ #mcɦADXb/J mS{v5D{[gO%pR 탨nc$=P1m-JN95}uj)SMW&z dabٸ6j\:3zx7m"QyO #}0.cϳF\َ7J3N dZ9 ub0`&αL^ 5={/$b2ujMÂ;p큅?E5x+wgA}ͱ%b#__b\IxEMAX6F%;U؃vnj`D[+$,1w4~E׹%7'7/_ xe~Z"?Z@ݽ0TVfc9Mx\ll8U ju}mqĶ@3eʾLw͇^5X9w#DzE;:j7..J W:ytQ]]FL]Nzz.&,: 8z򱆬rG HeҶ[V;*;Ux`X e}8`VBH{ӳrk!&`٘:X0gimܳ.b{~z .m "ݤLr*@{t@t(: ,[l}90tko>უh&s۝A@ 1.8AHP5 ϞTX/B }5u%KH>G`To z7˛}_>_e}-!voC} +lT6}o.P!1lªLx!\ҥ`+H9Puu7<;snAd6,Zh9UGloK⨳ _J}pj|5C}v%F)j>jz?utՖ nyq$}5B^hKqNv8*Lgݘ ZgttW\. 6'1{ ą?G;aMN &Kc=dB# R'!7I -5}#Qm`_ /l7HA"NJ S_WdbGTJdfPa/߽_>;Tpy}> #pgt&JGAD綼Z;Dqdk{G/UFv0]yM/ t` ڶln0ECЍ5G۶Yɝ\`c-gµ8i^WQT+.y@81L^ZXڠܣ|zX4"-g@tCOpj B9c8 ,wNOoC @ړ.ڧZ<檚VghB5G6#i//} -a)OvVVe sR"Ckzλ6s`K5,w Cu,DLsU‡: GY7>D@-WlOHn7>~yu쥻=6CDVr,u 6= @:`uӮ`-lR|C0pAQHݡ0V+]** ::Z jO plJ0~|uͱlZ}8UhklÀ˓WGU_/WZLf Ckfgakܭŝm5q_~ Ā{riE6vfWW-E+ϱ-w,m:hj% s^懚b:;S?f\|F AkxoYͦuWn/~n'ݽ$e Yw:l+2״ny~|ez},y=i3)}Xv*]^>޾gi3G5YusRk9d(km-1+l*Ӝ{rG?A̧O PҨd[8?nHBzVA>jHoPk?cѳvwJ3 =65u<#|z9-G(-pc!0)LL,l+fSY8KuP0r|t0Q;j o枊1X1 (Ґ׵Z3wLan@g-=ؼ_wmP8aC"{SF, *rlku҂c^Kthi2 JO4 wLA^rǾsDUo~zkwKBg #a( 6q'C$NhsEE Xf|rt 9ٞPXKnџת5[?5  {*m"rz3tKQ@"8j: zUl.c+i hƃw}6}vl0#1m f]ae=hʨoF 0S '' VQ^mMfCﯚO|} & [UE pRT}cɐHoxpK0vw#g*&-}&ˣ[KUK$tuY`ʦ\WdJ$ bT>D<\ii!`[=I[`F=11Yp?6]ԶsW[9q gr A]zḈV. B6J4A Q6vܨژwaG>>f2r Ⱦ@aZ&W7"í/*@ss5Zh~?|ChoWU[s>0A?a3/RC(਴@@ Fpb</vѲsNzG&]n\2yDs.朢>$:2U<3.BZ@g@ƾ"on6dvo q'<՗o<W>{_sXY JQFstCZxվBo;7+H(UquRɳ /tvwp_=ecP|&4̐F@NύlCuX;3̈ndj@-=#Lǚb%&:{el~-\'Q!­N{,h^U,29N;WJ -䀭Y@<|||c03&4(.p -}vV`nts>GgO+RZW9f"308}RA@dO0eU5B ]_$:'c'^;7'w>W!b;{kB@1>!`mFff.o@$w1xḇq7,W-o}^N3m\y]c6{m5ؖcʴ*1M5YC;t`b*6woSмEu&[8mb;R $C+y_^UTIK+Pu%}B|<.ўНk7?}w_NyuyNlBxDFu$S,mhmN_TF<x[Wg5NYДv ٯo" մha2}::Bn$gBp6'\><@$ hflkYe oc˞2a0=/<*8>yngr6ճG]abeMϰud&s$71{dJ6@GDg.n _H^L EAn'Iu7 =[l8#440Ġݖ/3“m.&y-QLeK88'J3 jϺU͟/^۹|~l1W1F(k3VCHvr& E@p|Ɓ/o1jAv7/vpθlk ƹ|̹Rİ%˽4(D/" n}hS, 7B7}7?>|>{~(le@j}F1 91覘@llor Zl].Fu ƭ _pep¡.U{yR If;J]hBE{`L }љO>&񟽂>|M7-t]!8qF`}M/DAIs֝ŋ(Y'mP (!ڐ&ø%zo>1r44+-ZE[$c,-k Du5"ɯebLY!:J'ӷ4c8_FisABC-tvz ZWT$)[Ȗ)5^3я1Z+떒ռ}}\o?ݗa=s憓0̸739.q\ϷyMﹾ[_~\~4 k $2\zݛWAPӵ1H pӨr W%vIjcr)LZ+nƤ5X^|$e.[ų%X.aŎSD!mV0Tklc`#G8g3}}X3>֟wK`Τ}pROwGF5yCu;gJdxP@-:4T:.}ȥiC}~p`Cvʆ$L'큗m!GlB&>7DW{a1Aۅ`:dsl0wyy^>wnQ?@8K jL-8yOWn `:GvjD`Q7`7'Pz3jEv ZMZa<Ң,7slɵ 8)k:MJ;c{J&YZ ŅD Mn?}yx,{|ݧnqn\5Q_Թۄr8ׅ mj{4 cә"G狁tEE8o>+*UEj0a[6xӜSӂ5%A:0X<>Ӊ0f"g M\0iTG!vLGwDR8zqZ 9<~T<#1y0|J2h˚$ S?*,L-n߬՘kc~4@k !;ƶr!m. :(L1 2̽Mfj=]m`-^7[(4ӘdLvl=3X} hw.bVl~@i],ıa~Z!orqZ;i0/U ^_LSN=6jpǺ8P1MtHb"J -)aȂϫmm Z3Ta*`쵻B|G0P&؟q]0n\Npe8)lDtǂxfWKL|"x}ْF`܇(X(']2 Dzr<+G6+s@QS8n&<>2f4bA1IeDV6i>ۧ!ӳqO0zJ0J0ΆU ~2~Gw NL ^ |/ZS 3TtE4W/8xS  &Һw]na <=/ ĒFeR 䱪!ғqovݕ~]_~s[5I'?P=q㚀Sn2s@=\cP c3+豹`i7Dn]5䞽xO`qpf+͊%PcBf"q?k|hos\B\w.!>{^qHΆ^Yhˮ7ͳ{}fBG6!.^nX}CP7փFH n:@'Kh2[- 609sl%YF F/s5GlBR\lʱnwAB2P7rpw3%zu|Qg2u9{:P OHm01$eK>_ ƫ %VШQg# .Pzo r*EՄkw;$MKǞ ԂY[_Jj9qoEU|vl]-\mMpXvZ5&J;lp&|Og/g4H)38l(KA g n; "9CڋTȠ'#``=EYm)K~e] ˲/f";2 e{_$RfYjfdQYN]Z zT*ݒu;뼐-YfHra|"S{&F}[:<@QFX:gke%}o+x4]6Z-,g.f%[:xdҪAQkws[?7*1f',`f-D@7a_-TY鍬GcB]섊&ۊz8[4K@GߔȤE,$Αg~-mU7fs[hjhENpq -d :ͥ(S*W-m+U?Á*[m,fWpW{ß*jg' 5 >>x'b"Nw6LAL~lGu~ ;a߫e%'EOaŏٻ"n6^j+h1 RhP)DA8ى, iN9"Q׌^AwNO?o`!ģW5U,Vp8tbO9V#1'DlqCw5ˀ_>nm}ST@t` rӮZCiY ߡ+i^!Mt5`MF%΄Xn?¿4o?WK.䆖r(:۸1ȊrN7kc ptqPVm,Y 5kiasPܻ"Olߡ趖NW.3m'z# ójw0EV@r$qH_ rٽ:?1iPo>wo1+E侹J1Fv^|dy0i{zH_!^V}bEmUkPt2oǺ cȑp^yƖaX=RakţDf#r{W\:ז "7:% 38ϙ?/?}Q{ǶN1jn X CuЎg:㓈c~F#Iv%P+֤;dA^I}E-z*bҠ-er ]<0GJ>s)򏉻JEH'S\A[?߫[B4c9I6uҀ0t]%YH~άlfu[VeH@ǚ7Ec%n3"g£S&'d=eB/"0j!!c} ֫2_}M3J~l_}G%9I;!=9w Mt [qݖnjuY&A>9<1% S7zD"i#Yc5Ynk<VgB='ϵ83.?~?U@7~|'Cs -C> LNy h1ھc/a*nbvF;1Qd}|S.<"Zu%O=(%{3&⣛6P@Vu !G jRSO?k7~z4/ FiYIoŃHǓ س46.Y:)pܢ Ng۩yUcVEQ: kצʲKNQIuD-({8RXq]z>#Qm;n~T9#wmFɄc!#&֏9-v/ W,ey*C&;]klf#^Nf_@ԭrd` Ygn:(}2fލfvpSs͕LCLk^~Ooy{sͺ:fg^BxA]Z=du\%IY*geLzcw A?9Zʑ>ۢk:TeC7 k9cq6qm\wO ]]x cdA gGҁ~u.bt9uXjQj(0w-N^N.n9s\(*_긽Uoji0\2Kig-(iYٗe~!FϕD^ŗn#d~Kl5Q: {}9gIr(YhG2!+ѐ€>>j-E!(L^  :1ζ"@D"ӆzmAm.ʡ=g>!yFѿo⾶Əŏy] c' 8a̍6hVE(S1Ő^ɧ~UVwn""s~ai.쫈ҳ}2'n|3~g'I2eAkzy69H"bH1ʮh7$kzgΫ~i;/ WaTCA*<֏WO_3ZKo(lJC=1JuT~MK~&JwTajy $^.w$6!`>wӏ篺v|txΟl{עwMz9uwf\d+FV)}{^[xp,9HNBZū'+]Sk6=^_-]G J C˜*#t@U7N q+X5+]焳UxžRoh=ݢgw%Mq7~nR/7i1mTUIGȸYnBˌp+{!Q%^ ADY栄ܳIY}xEZn}"%LϞ?ݫ͢H ~J%d֗pq5ܗ_X/ %;-gGF_((/rw "\6;xϽ>mVlydR ur^RЉ؜e1>/7~=s{MW?)~_K@ RZÊg{3.[]{͌sR^>DWcz[B]HVNpx ;>Y:vۛFIK(SiWv;4KHy FmEԣq^Д6l]Q 3a,jnr}:/k5cܩԺnitڶݔoU]WS9!z5rtC꽙biX0K.={topp-:ѕ[/)YZU!fpTT$[ l1}tqa9clt4w乗bMzUw윋иvz/w # in]uv pPZ%̉%n;IA;n\ƩQB8oJ05wv/\\- ƒRu$4*l8˜Ig&L 1z~ι87hc/jp=9祹^vy11";!Nvڅ~]w6XziIe=FdPA{% >I!ڻꭟD`F:4m{R]ʼHBMOfgq|D5y3b8*=wߴ C9_+GT%NɌ[qn"{V+]RI;.sAYJ_; e = Fy!#c#M{tkBMk^dSc.jlqR&N_eemRCh淐:Y7lNdGG' ծQժ@Jy3G HOCUAF>^(bg}c>ZYpM`2lҵXײzQxģۉa'/~MwT=g i\;wwV/3>44aAdmĒcU@KwR̷z esۅEYS)Ndž-j_J >*;I%JأsoEe2p0/ Q= m\[jdgWzqmlk sWj Pw<גettmv\LHgE,iܬzevAN16c G>ܾ~I  [$e[r>n/tI_Vf[\@Xs1:㹎z׹Aw5%vF.9dm8ornf:,4ދ^V7ͮ-3`ȓ\VNL=* S^n'ވFaj-5 D´UDK<?pV5x / *ӝ?h+y量9L_ԉOm}g%E\ݝ 䋈eyjjT %oZ(jH)qvVW1E"XVӏmʵExrɤmkʄU ҙy7>.~専0/V+;z_tF)f I!Za{-֞g'y9ruq׭b!B3ӮBN2k 1DGYKC/ Ӽ,7.j}W_oO,qcLj/Ķ<,^x\"I>](o|Ӽ[\un*rE=ӿFsxQ>>afar Mj]xՉ ׮zJE}7c #@*{o6=@b%r'-[x:zvl5-+kiҪ%nxB^ Pcz:=uȂQ-+[>Ą:Ԃ09ϼe9${ h0n߻,&u}~G~~ an@5Co"Rr M^q;'.PZ6F{NLT,у0 I;2],)m)1F2a]ltU7éc -&RXXe]XOy+VՇ3SZQ KCj+@:xjk&6]a JFX eE+sJ\>)OLH2L|ۤ=D0Ynb~s aL}#"B+ǫLhRHyL ֛SMҶz]%^mm[Jqioe|͓|ٯ).sVk1y\%N.ݼg;]Hu_ME/EQhL,\a\g.N0-ֆSe c5ϹݵᎮ5U1amJ .\{wN0mFR KIbtQAݾ$6TZAsڼ7i%T^"iTцM)-Zr zQo,%69l^ਙEo::_ aD2?%T-vg9GLs2rkgUX9aP?2D}ֳW20c0Tn.~Yn\P^SMp"Z'1$Th]i.fv6n7; VbDSY L^FZqC|Z}q241u9Y^$YP鿖F\)j}IM2^g-Z>2S'Î%<Rf[dbN &zrԚ5k::!NR1oHF%ogQ vb ^e=~aǿ' +FBӶ݀_󴹌\/jVj/9P if5yWewNF>ku"0LN4=l;i xk[K&D;O#b)xayYL$elƔ"$ zղ bDz瀆ȕD67z߬p$`/'W8c6?_nqYUW\!uJY5juXY߿$ 2aid@4ب| -d+ƻzgo(^Zuvn?tB4{ `ͥ@\nvj- su`\5'l7;g7ܔg5$g9}z0v(|jYu>;zئMFcgV}Iuܫ]np+0j'z)thA)6q=_gVb&Y6&czp6WNqFhuߨ((r6wFKqkKf q}R!)*Qk,ERyFySpe jm^ٌ֥ 52d|2VaS$P*Gs4L3v妭gf2o(d]gG^YOSɬI\1ভ#q됩]bF#8j &J$Vpl@Lj\^.-zp#yC"׎8%f߯& Gj&E z.cʋ6>+k8vX^!eCu|&Ee2mmg {@j.{d[t{Jkļhc !\DLy8XZ\mDE`v`x3nr#4lW,K~&ڏ1b'.Ɲ;ƊU!$?ЁmhOrY΍&FputwLhUd9 Ij1Ϫw-ݮeˈ>]]IYMN1<, B0 ML-mTx*sh+ԠCƣʢkqi2;+n>1{oi@Vk ͓2~_y%[pT?-|& k{:.w!/['2;G5.ϛ/hEwާs *# `dLZ {zԓIWZ) 6KE;^ 31XtzDFVu܎Jjѭva}k&e۶Dl_I9E'a8L%G.s03Q2VkD}XsŠ |y2䨥wbcw(#4m̗]f#gTL%f?PRbl֠Z.eKy,*3͂6 ?[ %1mMNp ~[V"o`piGâ<ܥc=v[=3k/p9/Z&'<9-| pwrJ$R^aDOW/YiXG&Kyն1$+]퓛 0󞷏Bߢ-84e..fS~NyZ쫏t"I+Gk2vɹjGTJkNw;ZǷUlM=LӠjU9NpkDN\)5 }o-~̢ww O; iF{Yۓ\B[g//MN;xֺ͛EXo6֩_jl.9mÁZg; =1$'^gQ/⪬Odkc0xڍ#\Bpi7 F1aif^ݍkpR:k@CPŽ_XX3lF;:pBaǟo]~> qmS$"#eAN~0]ט`D[= [p$U?٣vTcw#aQN5&:DHxvS6B)OQ 4m!`cT 5F4u=t՘fSWa <#BWZv7;)ܦg%Ѭn=!,_ωEH0PoPj@ͧlPn4EYWOoiOs4ʭ4ޫ{ &d4qnU=NT!M7nStLj-0xsDh)sOZӕ D*4p$^ Kt =8f[!՞^/Bl jeʂⶖd's^dHB_ b 2EE$b^V#&F?* <=JfmjB!T >,VU\] $8.W1E9jj $~4-"Sh9ֻu)sa-xfƹwS>k]G;@HM9[kwuClBרYO Q"I\ܘAiM#=䣼7Q'#2 krh𜕹j4Ɛqu/W>@TT{.=FSwU$NN/+4 9/ 2[c-zec-'Ep Bacܮdq,7 @r<5=sV<$mcfbĻXIU]uw݀:hc|$F< Kw0#ݤTxxAQR\)Ab So%uTyԦs7Vf|b[V)MFߤb1ӷQ(mumL'LPkON5 =>7Q;E`:wzZ^:)X]*_^ L kw=gT^#<{rQp]P9ku(&7R|sH-EK$ԗH|&ͨ3{4ٙw/",`,+PZwax6OXEŒ͆X̖.AJ;[0^hwVsF+6J Q\1$ޫޜ؄xIa>Ϟ_M_o>']N5HP"HM4pGC:LI=N-w vhcػ tpjZD|z-^^u5a֏|IwBV92cpSZb My$6 vr^)V{w1jIJo'!{7 ,f26}/K#88G7| uT)+VaY,`(NX/&{\<'k7<;V[]jfuQA̱7x 2A˯^ s%3E_P$]G:Fߦᨬ8=MSrxgE&U!`~LvPn|f9NWve ngIgk6>B@):H3p ~nt_&Oc\ggKKОb]IٵSeYA*"W'u59ѓ\34"NSֻ>VTO%?f_hd @3 d}9_{>edXE, *xbƉr,Φׇ̤mԞce]玂$ d #mEnUdmfg/WyroST1HNcء<)+͚ROʲ}ŋ $AMrw@[k^ɴ+$Ekou-#R^gOV!<|x)ڮ p h=ӡݾc/NcpE9<, g٢>x:re6V?\dupm>K w':HaO11}Y@Tl׷YU4j/+cs\װ!^BLx -Vg\9o2|6"ǥyđѭnb]teٕ7*4^izw$x h)qYԝr'1=a|[xRr\N6ǶEp&ωaRJ\("XδOv93{N$wאKh=AVS;dLﬨwcR: U!N\+X .fbYmxl6@:XOj k Gnk޸HԲ ,|:}̓&L7ɷ\Dj[(u8=@Ib峀 )ӄwa!Z-q_sdsNizI ǘ\qZ7fG!A’큿+qKڙN;fV ,]+;c˼Ѣ[:B9!+* 6"q_]),s'1ADuz+dpa9"ӻy ze }-4\JgP#TkI+ |NEVFzфd+M0!{4+20g\gln6ږ xC$gMz k^rEV[kS .Le/@Ύ>'[JI(Lwя 6u:q-BV5.ˣ!ګEzǝ%=LQ7f<:)>ܦI.rEHD;vWǼ7@|HDۖQ^8F%WHcI]*`)5UJP&ΣJYJU;rHR`İ q{@N+7Ti74\"h2N aNlqW{*d a?}}3B"D\]>` Ӵ%_po`yُ[fm BΪV6Y -|0~G8R=`?C2YvH -Qxsqe f%26Wh"0.kI٦~i4m >3NDABy[_jIs-Qow$h#lE`pO*}JsxؗYXni4h`AK$s0yC˜6|yժzcE-olUxQځ5YfQeB>6~*Dpw'&?[#Q+4>/VxnXX>QR,Z .f5OMOd/}tj6)z {:[T@,2݈#ĩB/5$8rA+:‰9Z]KX"fГ(kOX2i6WR}Y!$(8A˿{/.&s%{FőQXї7x8,Qp/[$n$Hm収DTJ0rSDn5Z&G!+c:Q*K;FѡBܓ$:( =Sm4%McFsIuHNJO@%кYS 'i(o&YŠ 7h& lr+'7ɣ8g:" Z&+{G)o}| 7TT[Tk|:m7u=B;tֆ: Hq:7EYX&cG<NBM(@5OtL/`WK:Xq+-ut1^=Ẅ́:u6aᘵ[hT?4 C1(:+ׯE[FyGtJxGR\f}+Hy2*Mwi+v6{2EP.:$AەYsȁO'?!1b"9vht[l-G]-kŲ{I•eE_qqk$PuU%O8U^|}|Gge+cquP(`n|ljZŊ цZ3@U.jQ|uZid6Ek4iPJb I'gK2ZeӚ 'VRC2:N_W^AOxP ^uzdϠ;@6ĠL#I bzeI` rFbЈCV5 swr$Zg2 Qlcнi \Hu/J# E](941HæQl7 #z> Yz>| 2Z@#d栌}= SE\mpym sBŽK7[:;ҮOw\xK.m/:ucI)d q`SI^*0:ɃO؎Y>wv[hi#Z%@):`?:3EՓRg2k&c/7t, @U7$2p3Hy1|@C,ۈ5 4zY FCKk9Z[l8WiYBGYnhg',-ΰ;qa#̬N;Bk|G'ĂޗFPf GC|ChYNӫy-'wn<',vW$B#qݵPm=sm|W,k[ߑ98gE ,9[0̺{^ؐ= 8YT;)^)7PPg诖@3)1 SϊJteoզz}L'zm߄⨓JI|nəc!C1oyYz+欩!J"@o~Ry,uYBkd-E@FfC/wc8Vc |%3Hzx*B:d y]E7Drga1X6 *zfDZ8 &!>`0k쏸Ae5w\!eҕئC!.z2h YΆ=Ti9`d1}u^D<#@JQ"&W~G84|5^"|ps-z'x}FwD+f8f#%#fsR79]$74ֻcV U]LlHq5]+mkO`Y(g^FOp87ڭ[kYDF#b(]P0~z}!q&L-gAcq̽Z&u TpQ@['^MRAs]@} RĪp0.Zwj]\He!WblU0 FYa yHг\J睽3tIJc\ؒxP[|. a6Nap4B( )pvLYPҜ6> 1 ?>"_ï^]*Q@ŠR|:wh (?*<'g D ZtTV_UWKSm'؝W*%Fdn-Y'ʚpV8@v_jAp+".ǭ{隃eC+HQ؉IҮëA_u(b8{g i Jq?iټgzuTFwe^$hh`[+.!2̬#xb ;|; sg*a/~TNuD0/݋DcA@s!x"̀)6樋 @vQӮBG;5etY5qzM1\׷IGICsƏ`KضMg)SpS"yʆR7WsX::cBLc'jc;TOy~C>1N0 "OXa3KYQmWcG$>Ql%ęp=ƲzVSyk/w,Yk2AH7"C74*,k?6x8og.H+˛G=G^|+FĎQf|N-%_2&6%kD+rMOu88XdIVB3F0 =,hc3b lvCWtXs>W9,hHf%3U̹`g gQFdW͊ag}FrVŧ] L<κRVVƌb^p+!:4133wL Z<=70*S 7T d'(g>> #MAbp^-_Jƾ&?qw?bЦ!8u'MR˗%J\e])(3o+V VJ8vB`$OLJz!_}=E+Nnמ>%;8A~>gv[)5?Z8Z̳vE/hgl}^ېG4 ա*Hԫ _dy>,M5r`sh X)q40kp.ˀv 0p>/#^\1dD[bjqH ;,05`(z5|bbȽæ4BwnkFbMSMFUq ) ?Zv.%- ZRZ+&D`SSϲ㙍ЌH{{-L|cդ}=#hqVxE#_8rn6~4 @:w /[o.q_Ӊ[[MC[ftHQVsŤ(N=dZh5ԗqZ1 @F$hJi?UhMҰ~םPj];(iAl+ue$~+^F ;WiǖEKfc޶0pV@ Rcf$i_vd)'qBhe#'J6Ȇ..3Ir0j$+1w~ 4p*B陆$ݿ+% w̵+C>]$vpT{N ۄ"ؐ G;}˵2.拉vv#?J=;NI`qۺ'd39AS .u1OR+4~Uuq>*άzĂd%61qO1f^_* }O_"_9lvO,㼻^`jž;hfLtXp0!L܎A+ŕ= Q>R2Mc\C〳P=r{Vk;X>0||ࢌJ:S 4lO>mG'IxRe7;8yR8tFl}jg>lbgmrsݒ45w)"4* ]E٥Nz(tf27[kq}cݯ>@𚌗W^.Aj&nv?AxqWdw^xN|`~L>r79^.YH ow$l:AUWU|Q>.!qaQv1[Iˑ KN2X0o{ĉ}9\Lx'i_2; 9\v;!e?R<7w)[]dcf~խk] I3qYbA+cgIgCb0.FY[>NȾ!gBHdYj<Z(㤟IݓY\-F)KmKWWp${F(ȅTcAՓ"gRMr'~?l6 Ƭ}鍰uzO6IIyU+}ȯaIf}fZSc̽* -G,`+YU 8^Ab-s0rgB[.?n`ܜ(؞½'ZCZVNްގ϶ūL|ybW6P6=L 2b0X?Eth\Zً9 R{Xw::q}f6oڪ(s 8DV|F:,Rm]PB,*k\x Ke% ,= K6_+Sۼ]6/d&>W]q/r Wy}2ʘ" I1]RYkUw1ɤ0__V:Yxm-c黏gnCd QXL#)Ƅ^?ܞKK 㬮kQ{#1SQ>bq/M ҬC]P:|q0IUzĩ ؅j-i,r@>q]Vٔ HZ2Df3Ě֚. GB_U~SBo "SNU @P= d'sᖦ0X qYO1 1cF452odReKbw㬱\@Y,2Py iz6H{I~b`dT,h{Δ^aF[ö^]ςHeZ;W`0oEf.m~V|GJo.swaΞ\IJ8:zo7Ǥq>A%nZSeU0 佷+;/'2JR@d8LaS[w"mtg:_髽y,AOggWY嫸“7f}= ޔ8zsU1fW*$tU'mR1T+d+fFM$ ^콬.-0^4A):(,-0LtJ݆a7^o [AYA,]"@G*F7BIXA>bTczfCPk1rO [H!m* L[ I'K`Y՝}!nsQﺗFq$ ]/+PZѝs$-^LM`FGLY J:ݬ̅,40Kv0^7u/>ZA'(|OK1vh3*E87JDz ,E#TPqdhKz5kv`.cZQ/)֝zkr} AH*}pMoui?(7ai GNޢ m>/N\Z5w λ㩞w=5q6` `Wcݶ09q "6Ө4;r;Wr\0DNwOd_!߫>>H7mwDWʠKMWΛyG*2(Y ]ĬK H 5X1Mb+,cS(*y7^ĐnNyǒKFŢ-/axAx$I@A=& jaZ{vꢧ;Tŭ3``: gz'm8eә,]ܞ9S_t-trgqʸ#(A;rM^T''⫶O>aAs*~{g>%Q{ v%F26_U77uQt׷ qO״X`{YA#4Եk)>Zˑ't,9 T:f/:r!{!2yI؞`qa &HF@FP%FѸsblp݈q|:R-s%]*H%_@ry&)I4A-}+:2yX[l{`aDi{̥֨m 2 Mkr($V`؛bkG19] ؊hبkRޭBTF{v!<[9X05V2i.wDϫnj\^Z z>~A6}6=̽\E{)]*x"m}:$S0LazkX":FΊ>kǓt8PM(FY]xzIձEԮx uVԉ:a!3_.2+<5AZi~=r =z=XqLJ_-ni7mH7G!H:=c4gݢCg_.ck=ę1h-՜cct,6tE%[ގ.o &{浖j CE gye<`$)ts|W\S֗7Y؀ JBuq1ۭB9au'x.p$ϝrUkh'3{@^ ;Fe%f m WhI5^ೊ39WB! rx6z?|5ٜ!A XAt:lhӺ Jr:#1y;7_'1(.OAzEcN֫n 9ᡩXcĜ8 e)0+0fhHuNwhXܚ9M8AtDJׁ 1kz_>LqQ3*\35#$dA㽗(R6Nx {I !3cZ̿ @/uSFFJE&b>d6׍\[[[ VNU *; k#}wg W8I.KH/{<(zp M*8qu B^"XzUz.Q[$5:4Sݖ8sﺾ@ P:1s/l_N!sAHu c;!P{QЗi(%ۛWu#݊QTaTIj4DTtr+L?~(qD6 /;Ij ks$mpyTR uDs?kfbp̕z=-oJcpM xk{^&G,M[UjdH%<!cAs mțQ&cF@Irg(p_D4܁y`?&i a[mx%da`wW[y`%6 y (qQ "33Zj˥ew۟ cXT>[95:SW5f a|cWCK4 (w1'7ӻ/ϯlYsw*sv9Mr3NiϢ zlڭjW9ZTc{ե.m4o[LYN_}Q({Q ҽ-q@Y ̿Lbe#=ڻ 9m2wv%2wamx;+|cD'|MJ5O T#ޑvGGxu1 nL25mTx"_ ؋,"aRt!z SehpH AgIœ~H)Diqgh>v"?"<|)'nՉKpவ 6 W E빫4QrLxpGJu刣vc,ZETElu܉-1|Ew[D"@EG՘0JΖ U Nu2=j"5pQfbOly{ j<9UmssrCC.O Qˆ ”4l):/d WJ_rrW{; Pb|J2$tZje\viqH5~F7ԼY$o^Pfҹ lV̴+guTڡW3 `̞\Z=Q0 IYCq(nHb,^tk$<*y x|'X L<8GۥIf3[ꢱ *Q$RgKTI^?]5:0񽜒wݸ =6OP|PhYy7UmB+Γؔ׍ءR{ض Aa1jY=0ЫZ~}' n!,\fd*LkdE4n+4yg]6 {]Eҷ[fץ bDZZ>N|Gho lsOB͕[ Ik:&y5kB=1̌^8;w`r(8s^C[E͘˔d ؉u$'|dwP?#+T郻 VөI2Nۥks"rաEY2܏nOyS0g^t;dF!_@^N){6voe4`hcԙKƘuby|I+(]UnkN9  4Z Jfs̫ϖ7`t(OqN %e\yazGTV8[K9<.b/oXw負.OxDTEˢfM yRI-ںL`SݪIG8d/(%63@)5;`n/`r3.Rj3spbL QmP1I|qQ vl.'g\[{:o= N:ÇK bTk_9۞cC(JdکDԳz-C&p'ڧsR:>zACi5sگPjf:8DƐ)Ү=& /xpRjT1ό?;IFYLf۲6_N/oUIsy%ti:'nclИ't+yܸcF9ɁzG<]5bz4~nco՟YVUrdȓf$ "g@>,T ôPouާ\8jCT ~9WBOx"9sxti/~PD!±>4eFJV_)%l!i6W'sSk;#.^N.fgGec&: W/`~N38`2r+Sɇ(LWd|zc 94Eǝ2!^#v)1) >0AmzK*Mse|2j'FQP#P6ߟ(R*C{Jq3$p0B 5EQ82=){3&L `RkIFڴ0ۆe tIphtm^ $'S UԲ1tCyBGQk[ Vɢ_z"XopəvU!&hU[&a) ?8P._ (RGļ%ރqXI1 pճĐ'&oTS~V1JGUfM94:D{kYrpHv E=PH# 0E}BdddwUj|ލލAyu{!g\keFT&!8P#´=Q.DI4v3DTܪ8WcY^VaБ)q .BZXbS85ixoÈsExoFwHֲIϥ>- %te+ghp;1>9/&3fP 1 X5蹅pp듓9Zi?Q븬pMHhGYߡh Hb:q-n-ݬByK{Y,ԯ-A|^2~x&eRA{*GLx،+;^_u͌ ue γk ba˔dr m.Hk#A CGT,A Kx~d'xƢ \`G\LVL(Bă% .!=(6c:+Q;b2S0rbx6.]4f* p4քyc )6yt 1spJ4g2_Sσ/N< Ba[^Zv5 2 H04SD-Od CwaVX}t; ^Lڄ~eLh0趨[TOˢ'uib6˕+ d(5Vf2Rsƿ׎|!H؅~vWhXeIHJ0Z˞AntdM`Ft?bHM q!9IݨCW@"ytS*nW>&3~9B%_*?N|si%L{y"5^t(DD+;e |s*+A <,ibGoU5x<75e4 iy*uQ՟ʾsTiA ϙG}=ʘ3d62*)bX!'X`L$t'LsOq9MQ@G?w^zן_ LgFj!W9Gj䣝rH dV`9 F *4-30;!ӝˢPJKǧ(*كo<^֗] 7on[p$+E "FI1 Bddy uD獜J໶N`#"i*9icU=4OKaktẑW]D Nɂ$)V`"V`u_δ(kf^^5^[:IX OƆY,ɻ3٭140a{״w҄e{h{> =q;H7-<$шd M9Hmľt@kF2fjOHo(V<0vN}a[)K{q+bv:&Lpq!Gqt%(bf92=P3NR=h6%&q}| O,YΐGH])DW k@϶khbUX+$~kGIqZ%#sSoOr>s~Ã~'+嗿㧿ۏ7?=y/?Os t{;h'I000FTN 4~+Z /cPkoVr]ټ Ҕ&n^Oo}㧯>}~/ߤn~?x~"xMէϖ5?wFY{oiA~ΊCܶNp_`ЪfT9b)&ڜ}tU*GUԜK0VoF~NnƯW#}|n}>ؾb~~疚>-,6Uzv>oбuDacAN62T.![RL㎌CL1xPK#}vkvoGQZ[k=&fd^j] yX= :vЀ$y H" Z=  H _e][郞wy=ԗx㗾ݭ/߽eksٝ ~J"6Be6P5<<ɪ(os1ٜ#lc#vd殴Z7}ZqdbCy`wTw+oX?(6qNF3e ix+\=?(̍ŅM)=H=xR_™ &"f tj |ګ?xgx{3"-vQ8Js(ģ YFv3]XSe=[B*I%s>Ucqv&:^|>񓯽/&Xs̆H9,[\V:xk'< udi y7Z- d+y3??#9Ͼo1/GQ?OW=cς?{ΣHO~_yuS3U ZYUK=Ϛ;Q,[4"0 N*ks{ޞ@"U8a:hNZ$.]/<^S7d}!=Gcߧ_T! μ0-@DC Hg>Ѡi:AV.9F΅~У%̉ZC>&/PZ ÚŬyh8:E26t3ϚF@D<3]# fOV#Fm9vƮ$UiY/jC ^ =M,DNoyݮmcN=n4{Dy#Ps$đb+aw RNTauAl9xc5H@/UbC<+; P)]KLA_"􁔸( o9]߲~_x)p+wo߹3[:;^}v8&,rZp,N^S3H[+iqRkU\}5?Zq_/>Wh5o8%5SǙ2:6= } /8+%~خpWsVU7%Nm@e91iX8bF *?JR!.U[1,䌨q\ZٕD sa5БZȀ$<.{%!Pc6tg yL r;hĪ&N'!EqGt*1|}qA4CRr P;¡_=Vk炰a*x:')dq5`n8vua< ͔H7D£2'oy|_`ZN{crm_N+CKCf3_դh@%,6yDB\tsPI5O=3Azmڛmj5B )d} WY=w̞;rUR$Zbn`&Yzo@)qtyr.{y{\d2QK3Q8fkF5QPuJ-4\b恘ֻ'?~Peh?o՞׹nPf*aZv6 B+ aoX ? 4ycweimfN7~_/7iD׽έ/۽單ovEy6K[X j0)hʃH_J:p˃2&;35 /iFmA0s@Ib0ʈA Xqt;:,zh䉿xcXW yT^;;^c8bd&m;;1v%Pk5`g]p*ApE4Ѽ+\wo{.8K֗ MחZy7Z*af݇^hH.|x8@ .2ư15ܟ>'Q* gXw nL~:LvԾbz?Mˣ(}4}40 cϭXV1N1D4IhuƵiI[pA71`zL-FmEk(˿ýoQ`3hGBbjAp-6>y"L06UH-9)RQ/ə]E\p+2I(%BkGT>M]CA(yZrwO*z ̂VyqwSlNCdɊDa fVαyӭs#i1GL9ؤ/FKԆ@Ae#P#=#D̾Iq/Wc9:c$[Տ^o+q둎i૟N9?ȵΕ@Ą5XOT[iÀ@1aɮX^=GM E$V`/fUG:̥jz囏_ҧ' n|cN_{+ l}7HH9c#{l^ aV36ז3E5hp!l`ԝ(_ozgڻ5|C8֓[{}/ )N/;!/^֗^5%_ܢsL` ̪YF%`iG5kͦX@UbIuo1f6Y y=*qK BG{q}jѽ?]?y~v۫2\FFgc$ Gb-矲(t_ |7p_'ύxKYĠo },cDAhqONud޽B*rdd5n9,L!!q<'Zo(V/~Dm\5yjFKB'u).b#4-Et\#,[ {L{9T5ӥ !?9$|_à_0:5=o]^/}t=?7s]FeSPk lg>pIkbX,0u,FJ&W"+Reܑga^]Hγz!=[|o9 ^BC5\ Kmmٷ-|0h%QTD{0' %b`^* [r;rnu䕿|Ş|`/r?z:߾wa0"]Kѽ5 6\6 6g^n3dNc$9,Z 㸠"x,6cQ' U {tԧרa϶w䷽x@o*Aեƈ >KsbKj :BWaZNllMPMRP?DM8̺K/).{6;r6&PZ[Y1Zmo |okqڍ8OGA+F^٠4A]SL}_\u qZzhmud곴H,971wʫ:V;t<¨=GqU u΍v8eKZfF 3ǖkX{34r=j$ܾ;*; ycp:@ͮ%&5^Oh~>5) _?_Si0DGjmʹж'/K/\ؐ cZt0: k,Zs]8yVG|\Jt4P,M{|j>[HUxCY):bJPilu(ۃru=7oƨR%k%w c#u-ȓa.JaE&Uz,W)e$#D1B>(崯N ;0[q ʔ͇v L{ҶRKRbûמC@Z]׵5֓&XpK\)()@^hD!lQDstW$C0V$x̀+&/s1u_ٍ3,I+ >[\ !ܠOƒ/ \F :4|h8ۼ5t!gv-Y"SұW! ;yN$;KMF]vdy1x\ꨛo{m'gsaL55"+['խFV]ww1cdy g?P1=βgLӧD(5[<HCZv9Wi hG hk˟>[r@eNǗ'[ a'cēKNk"!GFkeZdN:~VC #Yg)tg-%!s8ΫDۭY([gwp:PϢc-tɳ Phipar`bJ{`aSN GE4qLi|)pBW2F >Ƙ[[-tpmn;z9im mIT]] SAS 9f)i(WUhڣxVSR3Om!l"D,g 1#EC!r'w睁JLbGv@Ilj5wy=w=Ղo?/|O7?ջ6ҰnHiOu z(_Twt >u9XfW"Lt[ %Zq4{GL{olks}C/"n}_U,0Xְ'޴O7)A&V 226[fv+4Zq{6,+j,^j%e WݺqzŽ|S}š{Ê W+.+.u/wpNe 7̎GrRw)ڊLS Kdxy'eǦKfj\Yrꈸ#{rNS>A犹9:n=C @go}HcW4wqCJaA^#U],C-5\`XYV)gŲ֌j$QDLﵰ *r*f/蔯;&~Gl?Ѹ?wDeᢽ0ch4eg~>Ƶ-Oq&"h.[[kǥ>Zta%nUk+=DҶI;S%{lOOȷf}}coˏy9i0eTڗHSڙ D#̱gvwHq6{JÞG\+xfty(E5v ,݂WvuWy_}dT@5 5}?d]ך֭$F K%LږQ[i[,1V,楄_X\krn({t1f';HyԶk>KE%;Yq'/c,a5&c5\nܺ}ˇ/kn}H~W䇟@kMs8gW1(aJ5]{lA]\']%G5t8#9u"&-)@wP!׶\Z9.fBRRU+|J0%xFrjetcH/yyp3iSh/?6tYwRتYZ"Gٻ--I8P*тRr&UHkG ZѴ{_wSfw)N=˲̄Ъ1V1G4F%ӵ(Jn}zMZW-kjn}1ewo7X3_O0 \Ìa'#8bPL}+m{̙\1דpT6Q`]ZG`j^r_lj 줯28]*#2={sg.)Aڴ픚uXȍp(NN-Gi*SIla{pxk(3ݍt<|>|k~Yآy3 ZjaVJͫO֡SOm8y0"JZL+ 0 `N-r]xd>~}~/O.͘%/u菵}AviMFܖƮ`6C|hgT=y+-&Xdu܋33Ӈ[_/>1^@C GnB^m/@qK9֑KUL.S8-fAiY V513L7]__̼.hvJVI0 e/ Hi-7`?H(Hla?oCg$%fgq>_zB n׼.ϾK {EFcѾVM}eB}YLZjtA[ Vc6f~` ukت12cۣ>2~ol֣AW7O89 W^ޜ獯A?јk^`!oJo]3ϒlhGZ*emiz*ԚW@IE RW(@)%/q:re黲&&CiCk L49fƞTLmLv]ah$F]GӘh3m&j&yk^l'$kmAre(sfb#H6rvcyݘm%>ވ({\g/!搳g }+8u?}jí/7ƿ矽SJUG3F ce`ll+(*lsYp.yG}T1ⴸh['ˇ+}YkKs .CGA"C+ڊ8ru!,Y)U^k3k .ΰ0rz(5TV ?y.k{=g^?Ɨ>:D!wx /ݙ4ưy_K*԰C8JӆQgKma*C[4fZ|nz6e vH"~K~K4`͡Y49KlƟ%Y123`ιV:31,0G#dY6]Kn}N@T_?ν O?חol1Y3#_16y]U`甃Ea㨲x /\$$ձ:L!: AøaE1{)dSˆvsLE))15v .!0q[WOAA@lM9Z\hT=8m"UҠ7ah%9*U3Fe#u:w)uW}XfWKk#}q~-ˏ7?}O7⵺Cicyڔ9k*Y4-$ FuwD%@eq쳁yq:'!& j$ula[9U hMn}پ݁PTbtsoI'z9C#t߅dd)uʹ|U&(^6k$!xWy~RÀbb}5uj$s}zkύg%լ۰eD0Ԍh;>eV,l @ٝjocnM6w&vYÐPoޮ፟Foxҽ;_ AF9HIf\jQK{-t'Is{=9R̈́E9M8euuZxG|vT/(7xۏsu|.1 ʹdN["®NX1BȾ ʊe޵ѭsM;qIў7w# `z}je"&|)a~N.6'S:$ (V݉,j[1$Gi.@ ,)-zM?u1G>'O=Ѝ/0.W5f ٥.PLIQțDtMA.V7A-495OľW-k>K;KޛH(>b"-q)Hk#?}ʭ/B9bZzD+[9S,3UJMfE S2•EX+tݥ:8F_SZl*$i:dO-[_{͚(?/~4֕ZvUTHd!0J/~F).f|N ]Z1JTy/[OTwaP4c^pR4Q6eF)pϧAq5$kB1rĦ=ׂρ!mIx ex-a(QvAbSҒr"q\GU<@2a$ .yڢBiN@$\Mɬ>՗5t>7CLԴc@W4t qVE|疯S//=u)`Mhi zpYnɾU.)g3#{KA6|RvGI̗;ޔ6Z~NAүuĪ $d%iul =S@5Q!S0"ؠ0?xmI:4|,ud,GtKv(zJ,;@Ta]&1yрnm|eu%֭fmf1a\Q̣ \*"2v=6k +!ڸTma% J<((X,ѯjxk:a u2ַ{;h́& jdaϡJ#|'&^?E"=lRYkul2kAֹC K\s, ڶ@y:B']9k+@Og?;n99SzR*mVm▏CM([QmAXUҹhݑջm [PagXAKpWuۣdOiJFˉN V/Ep";ɩLYu..^[#32asq{=_~oݛMka gcGEixьkesrTzͦɏFmH=9u'sKdTl/Yq_TҬ>9gB;-OoGU\1GP=0oyur</?mzWz^ +[p~;p\4p kB<ڷdɒt娗 R2 -iyNU~Wg ' 4 |F mýWoկ^zGC{گMry 5Љyv3вmtBx48jщ6.R%ѽE'roesT<@:;pO7^nD۠&ֶ#k.maAJ.Y"#,g@kX_O;Nl+&dzK!ʿ̳_<v4J0n[qlTaw?#r<]vqIMQu9}M5G6' [xomL_o>y4э8>Yz.~6*«t3`yE,-$@ )h7z8onw츿իu_| }ʽW)PPO nְC}z腈vJNHjy'a\9[^X# !lPDTl͏\-Gvo3M0G}b Bwx߀ B˜< Fu9]WAB1>GۂDhv]3|?Ay(/?m@wo}\ ~;Z!3Zr7J:/1%fT[ "L }x=UeӀXLP5չnTC|n׆k9~|&}! 0iLkpfu% ꨬYz2#)k\X"Zyӽ7<~}wsu %Gk mp@@ȑ=ڒ5u]*qMH'9o嵶6=nYb6_=y5/>^ gԾTTh .UA3(Fv5{UujtTK5O݋ l:T{noڽܿ\̽ffBdPiUB>vl{Y:p(|YCt bizyFѐ[8pwܭg${_:ˁ8Pgfځ|qSNFƒ'E#w!48TAC;T)ZH-64D| ې;/ 1wΪ>&p-p xӕ=ۆ$wӻ{ "![f{? $h 'Y#ڦ`pl5qʮ2,|˵sXft Ed)30l2F]D[!V)w {{K7ݏZD;{Ba"b2j35k]tF{Y (; =#b!Fv!~Om7^gm{'Z!]{+-ߘhm/P֙`d9G㕉4S Xe L[`1eZb*e{hVa_' 6܎4t:(2eIN9 ӽnZ+q~O8 (fC6m0j!&!4|{o;Ɵ~{ݞn;>fL 3j4 8 mHOh2屘Τ&-b$xCx09PmϞ3 W³"I2m}I$q7tAB;m.A[7_~xW|xq|Ґ7gJi=]ɥ71+2C{iDjBls&(;]v@s~,}­5 )!kq.LraȆsA[Oz3gYdІ*GOt3wK#R[G{\nu/7w^G@>Pm6c0;l:9m`Fx/8ShDόal 9HZ* MDajD/ roPm|nvܽWюv_?v [ی Q{w:2Er'_x|p--\DOpq^$:#bdM|-1xiۧsϢkHX}9y_?A`Dr`Ʊ]woB3璘/ڻю=̣g3qщ:峐WJˁq!6h'\>#yovE0DT+C57lv$o4 ;KSMX8$Vi8Jsӯ* w >mK?-ΫŘLas̽"mxo_{w jO<@ Xh!`^Ga"G7M&HzxA `ug/u ЂEk[G(y!(p3ĸ1ũpD+&^ܨu"ڈES1E6N#A-\6 EG0;1|H^_ s ~vT`;YY]jkoA89+$+ L Z,0X``+.ÿ 68mȜe}Zg:7/&NB6-Ѯޘ/ QNTf܄ug5q;vz51^'1/ G0YGϫr.Ēв𦃐޽_RJ-ߨ(q_mzE2Z/ecGۀ>[5l{o:/߾xxU{PkCk^OsLwU?ԅ2/ NGJd-7kP-q6k;(lZq@\ی|W>e[nĂ ] )9Fh'Cay#޳I?LpҎƄIpJe-nFmѡ͐h;|/e jp7q+}Ը۾IO|>%xia/%UV @Mwqgvd'aݛX!_qχaDYl2}n݌:?ͥwn9 tEhH\Ƒ">D\gf@0xnm4P nRa>#I 7M!@:N %bUí-XT`Enpnl-082yd>* ]ǶH`<׷c_=B+{͞(FZqw7 k=iw}8k)qKk`ޡיu}3ӊJx00p9*EO,2 χ _\6:- &>:Sc2}ܓL3@%v2`Z}V^}< _y\.Ȇ# '3!{2@PD TcxK˰ly|p'am`Iќ ԩPғf~0ARv`ƐMA8d0Vݑs+f?g7d&=Wod#Ѵ,l])=/( ;vNoCQ57xZ=;8Y~ uhvւ"O%Pf##x@UJt^Cj35)HcY8e$6o^Ѷ @PK5< ENq4u`MP}ސSm^Z`xl ,OI_mÿ?9Rfdy" [;b{a~`nÒONaPjr6H}ͺ&575!b\Kn[إ~۟=9Iǘ@޻z?A$.CsEI̪kerk jiY rlk68$Zua#_ /q'zfZr^' VcTZ%iSeR6Ny \u,A8<̱7i_9/V"fqRQtbf5<[Ks{_q|:r^'tc?}`ی0حdV8Tիm+X1B[LE0qI"WҪ6Ms }KLvý|OpOp|s=~î2OFͫ.9wFϥrYG1޴Zpt]kD4.*>HlE#[½;@b럾:{ܯ a/k}鶛'O̶ l>ۊI|Κ*pH7uEpek٤KUmWqf̶LoZg)MG 94pM-9B:44-q[ꊤ=MRUɬ=O d d.f@v)9 d I-y<{*u-ڒk6!`Ic؋lٕP! x!3@ yku8G5}7%eQ1/ٹ =޸MUZ[q/]D%g͕@/o/ m֯@#EyӮکh"Ȫ&uau2_acERvΎ}uBP!):]-py)][yT9R dOoV:z黬BO J jx b1gc̔y߿\.K6n4'J{I GO6@ͣ:Ÿ\6~г(.D[6mF`:*#cK-)phVwa$V n u'Z|Z~ IcTU۩mvtZh 2$][6_g;; mѺNJVŗمmB@W9w OGyeUh. ʽA%HW}9= HTۖ@?#}{(@J/?JbVn[! `jS9ǩq4NB36Zo09`Z9ZH E"6ʏw֐ʿ~Zq{R7RϏAϬi!u!$b>0˕;p} -/nq:˒4&Sc_A ˉIzΘ J3`midZ5b#8L Jc#kh:F4_06 ?6c/Ke[J4NX ^DxbFΡݚg^DDH?K.  Pz ?.ux%J#jF; agdh۵卷8xy^? /QzOŹo\2MbĈM [i҅Al`L#4m׻1f_ItZ}zg1FVx§$ys;_/~QF_.8eW}٩7Ιcn\*RF1(0tH#}:O]ayFG2,мdZ!M~QDn`0֧ؐf6#ij~/09jzqI <~u؁Oj5ve"69Oq7$mJI#_qCq^{hCCb+aKvC0\c9|*wo{=LG{/ݓ^v(⧍qxJi Ag]s4ߋnw#g[R׌.6ĠƪGgA_/Sb;g N6tnX*x.Co(RLYY ƌqk\8e{o} &s`?W'u X'f#+5:@"estt{y0qѰ 1Ǔsi g|Jځ`ӫ*9H=ɜb.jد{YSctaD]xu7>X\ ]<'/w^'/t3}y>4h- [K[$7o< ea 1)隡;F-E4Zg;|v{+n6~ &^':AkAFF&} lc/l:;W/gzcF%VoT+lWi8͛菤cR߽yǏf~^':\z; iRb $Tk# M>@2vrYۇ 1a̤f]' |ˆ֨?@6F68 (rǿk`좀\dKuGcl=ةgiPbֲvn<>2s%{Y7Pg)sɌ6&vOF՝3`L\&R sl 0ꢦM)AR-[nQ{U+@ZNI"cGC.4oxF~!h/8(vESޅ&GNڳw9mnzm('ǏTi^/~y~{2>dWw|mweϏk6*%ԝ"rnPpq]{+:3vE<9D|.g4BW ^mHKvMzs^,{/jUsUmԠkqqw<ԐOS"@XD-Z >m1=t*0,64+1A*TL6;i:{踷Q7"Mw^'[o2SSd, qV\&m^=*R}ާXdbVy[ &Z6]aqrg9~eC'#ݽKo.ՏQ6WM&YTҵ3>p5 Œ2~xY_ Z7u/,tՕ4i {@6JOP6u( gІ)͎A,}$=󄍆bT-w ^`lboiC; 4wV^_'qpO&51~m}wu]9fF5!6( 餒v8ZBPMY,>V~> d9΅A*GHzY6Js0Ov1&'^1]6 gڏXzt/4n wV6A G;Sy8q SɖW[Hτ0@cךmp8CŁNPB!݇) bm %n@_+nikyJ@2v> -l˩{MġD6+(nƖ}NLjRgȎco|\|d 5-'N ;Oud3xu_GϠy?JUs5Gb l淁ᨫ$u&œN'A6|Qi>n u1xzP/=ci>o!秏Vw^')_ UWح%^.Hq3iHf-P * o3vLdɛHI)Z]bR `PQȆ mwdinq'hpĘBAk .봃|X[bp/ۮfVwo/O=F7>9O]%hK=n *M^]69I^FgE.ٮzZA^ML{]ZmWib<ڽ=Ŗ.,ƣP*EAH'8:Pρsa#yu$GF-V6;^e hިE{'c+mmtom{Q?z~#q{!$5K$`Px)>zE0PU6@\#hP(A@2~'&8!.o[b&GL [Flh'F2l3ℯJb>kBдDbuđbMV!al'ߝW" C^~lȌS8a92=ʢ7uk?eR3lokuGp؁^Ztuӿ# 9hYHfo7 )Ajaʊj=^:Zj2)V3fʶۖ½Aow 3!~w9Z˳09OsRF>"w|$عc08/^*1͂_MzrJx,g3 ˺Lq5.AUugy/y'9gnd$cTchA'cGoa>vlM<؇ٙs93j ˡc `BL-ݽ[ewU+HnFrB98Ӕ24⩭oshru{ Lx8tH͘i\)m~wpO 7\ rG,6G+K 5־qDdgDuD1woSYboޱT-Q|p  C:n{wn=~o_O6~xO ۍt#e?;V)BV,Ym6e K-lpBxdF*dt? c_TmnѸJ1w{ևgh5v2[T0Vs5/fR"_K`/1&UtWqp#u,@owܽ ?@+n.|ӜZAFgGm Gk ٴ{EGx1Y!SO#~:/a+:u4Q] \C<9`Ⱥ@-Ҷ.Ci#]+jgLY#G Ǻ0;o)2_\ď{/#>bk|xvNbcN9 9Ȍh]k k,tVxjh@OK$teM٦K igp᥌z=" Vp3I4BlccEu3jN(jE}afa콺wu ɭʄ^U5cIF{߷z7.P'TU^i*yЎs>h]!\r`hќ7◰6MZc1HNB'rOuosH=eh^ֱdoսzW=Vx$v>G:rw^'5r!s{|϶132HL6[a 6ۀ`C`Ĵ@j9TzҚmgL PBsھ|ݴev>l Fg8rdhOkB. ǺPfrqᗺ 4=\Mg̪&-}TyξWD1o'q=4^`w[<9ٹ)wVƙzuرn!iӼw`L.,%Cko?˗pip8Uv['^o'VnC78QګiiIjݻEk{"㍼`.g[or7.ʟ\z臿19 ,}.°)ְ-buL )Z03[u/!4O[`cYQƲVaP`ZT c8r&|SZ#XEp>]RG-bIbe1\tɋ b!߼͋_yxOO;,Ռڡ?ܥ}h~eh̼)A X+BFQjBmjr^ڛNit{Mi6lUޅӠ%D@ Iӳ:og][ٙf}ӆ!חʉF-%PJugxGVho~WJ_Ih;OP2֖A,Dž;%}@tB:V*mX$ Y5Ѳg|ێ.ۧ/=Nm*(է.BłaV # 6ȱcA9 $, n+E܈"B꾿=Wx;{G|ǒ[?Yp>Z9.qMC^Dqc{vܹXo&ӄKó6jJ|y,7giHYCh NSr855dNHm$nV.VsT5ȨZg]UcOcjk@Rj;zBڀY/hbM^yipL>kۺ{ٓ"꼷by|*d l8W^4H !3"0"UHİ-s*t1.0ZbVUP+W gYު57>>"+W|l\(#ېҖQnmj;tM)2z6xhKh*ճqhNQBNP6S_ۗٝ k1~{PK_xAcg6h@*ꡠc9s5T͡S_"۰5Vb@G8>U)dWYvڄkx3f@xKص},7Q]OTΑn:;j̝!OjapZUcpŭ:zL|5Tza\/HC%};Gm:H~.J4"vM0K*jԱ]l/%c Z puxG6~dBO#(sg/Kg-G vc z:#R=G>jmn=1ʴUuVxǏW9h[kh;00":^򌃎DЈ('FQ8 f8:tڲ0/BJ\ג'Y{?Nȶ&g ݪNY {]sqx6U7V kpuc0x-v'#f`pNV[W\UZ<#R %ti{߱|/!kŽj^`RG}A֜]gdN49棓x/c*W ŇFQHFQXeчCW#4Zkک/;^(Iu.L N@;2,)¥qF/cZGBcmf>?WLef\jkM E,fgS J2֚1gfS3y8 P8.'i9QᑵE[\%ۏH.NҲZIZiZ! kjշ l QPL* #uRpp{m˷/}|OdOMs}cjP( s5kVsjz&UYht 9qn8su`T])2#i8CQs}5| Oȩ e48BGsڹzy1@Xon ꥭg^g5aU F5&8>7F9i5rHn ~k nΨF+Za`|RTbTcrz^6؏HV;Ϸ7O|=r{BG1m%T~..˶-=< 5ټNvuVQE57>5k˯I%$`YGͬ%Xwܼ*33Rժ,@ wez`m_f`؂K 6Y]]Ʃ~f{ia)vLxu(ӄ0d |-gm oMˑy%t-ziwܽmi~ 8mZ<`D<&mg . '9/U'}N-F9iT=Z]dv)@.&S|߮yM\9]2{ ~W{'.nJLO]"Oq!-u_$aOS-}F%(spO' 1G!n(Fe9`gN[̄ȮwHlbL g B^}Dޅ0>gLxs|qXt1'B:ΎO_BTaj'uegQd{]ZZjێQMi]?OSP<wMm|ʀuYWT_s [+L>M=i o7g>՘͔ª)nW~f`:@D<§ir 0Lf\<-~;v;uq/ģ Dݴ~)L_9/i鉔"6ĠoݜMG/H[h`Y}5d q2_mo[aF{Mb{ezwɞ :*-wӗ;cjYK$]n*g<^vdW4P*Щh*{>G/ lZncXv]e:|4~FD`r6Z~˧ pu{ro,W"zYD߿pq#cԞ cj~ Iv:0D.+̾td07 Ϛ_s`` Ў3~ܛ5`;/߸or;OvAMCLt"p$`p:EUz'}ӻLrBhsYmgC +D&CHj-=~1K=9);I:-C;rFA3=]hر7 hH?7pPy=L104؂SCd5M+abl}×xСmȳdwgƜrrIpepEMh>?9Z<%X/zx 0Q;n^x^(k*ʅK;n["C=i,pRTcomRZmOXlɎ}q_7ۋ׋|g_}}}{|`p|jI}+'\gp}<ý#lܠpn4F/]}i"A5͈>ӹoArHP1ͩ7z[^F"1#ڢCb Ym9d <:DVM^#]bL3d~J0DV(@d9$;F½;8yFQwT32!C;ifXlƃgHl%h|Xqf FupuAĽk` wWtoH6f9$p7DcyLጹ^PlW,UV+ [ 5m'ޏss}x57VH(@,'I[ #HK.cYVgi)|)Hl#GھAz7Dc~O߸rįz}鎾_}wo? L0ՋN-(=NJ j*H1Z&5M7#EI4=:l:3SpEEyvnpx-h6U5֎l@d-6>+u! l?>Ծ>۝ =FF~bik l1 :zځ= hI ZDAkqIZ{ gmGgr<8ڈHH;$2783,A1DŽÓ4jXb̶ɽM vǚPj!̥ik>x;^tB]нR$S*ZE]DO/05s($^e6Jn΄oցiazƤkݸ__^ח~^'(=H#_|^~_>{| ! b-,s$Ips&\]FLjq6O 7&βWiMZvxR&-?BtGe|Zu4> 0sy(fh6:6bkй3>oVώu%"PwMat)D{ b)I59_^/x|Dw]'^lw' %LvVɵ;¬QMJ%)ugꎶ̂ftbߪim8&[zNXw'աg(tXs{Nz6:۵m̓I 05 ꃦmiy?öojN}KtOyΣcBB( bIݒ;>! TjwZ֑$$ iM6+フڙf -I$-X_8e>bl"8Ϡz!ègF]v8wy4t/ީ_~Q^'O!OB/ܢ-2YV۱x{by OnΌysu$fNۂt\r$[^t[Eu ZX k~{~}^ЬӝܜY%jZIJ#|{@]`3m5C E!/ |.~X-E _iw^'b*3NР ipl.B}m*l4]u7@jZcn*,6hk |w6H3ouu%.pݑ` #Ab`2 )vۙqա$/*LtiMauћ5vE'B^%np/dɻz5ZZG.#XpCE[{3\]Ы?3~OdΫĵa\y*?X?Hd^RA!n/à#Zհ@K3t13BWĔt,5B8͹#o_{?~T愡9L<nGiKȸBa_4E[.~yj O,Z6h=h/mu$Ao΅&6t[mʾҜ]m7-ZX AHD"2r*\\ `T鄎w#Zut"X\;YenZ[(\SWTɘjRxRG/cdd1WB7GǞ'FC,&ŚS8\09sNl{fZݖoDM^$½0Bls8}l >bG sEG:'D} Y{?έ>*~-'A߫jd"Rx1q |"p$+hV*;}z_ԁFe\:ߟ_32.:)آ|ߩ,[(n%8lrf 9| ˧HYeفXǀ(τӁl+ cӀM{ 5D\-x0fl؝QX KDi--ЗNIY#nhܻV}S;б/9ېbjum>!kHָ:WMWKY-yۯ߽C_<=1[чI@ɕm"]?S1%6t9 ethn2wf67HǗ$g߰6^?jncg0(~ MG׮cӤfW;0EKgba/]\:zGw$&05 6S'GBpy ,,q0@*@!+̭-LQGCF`TjS ~*!3AZQޛ޼~##؝5e dajik 3j9uLۦ׎{Wp}8y=8FVh;zݺ8 lR|m_#v޽ < iߒ;C[v#ц#rt&K}PMl},I=)Oj^Y9GҺqT& :\"ڧL0_e҆,@6< g?fesP!Oh8}J1M'~A]\RY*АI=˗6k覢kMOJ~/?VKf6nAq~$cȔ tQT}w5hs_W1z֎[\><ݣF 4;w]"R ̄ flӦAOFteCNfoC!Kokjkj(@B, nB09F EtEݻw>gW>Ѽ=銢Wԇpk3 TD8l[A\PI 8Xw>pbO xWB05_xdsr S wK[oab#%^1[M 7m1Q)ǖ<[{O\L@/IC5vb-Ə?/N{u{b4@7g,O9i@51r>Bjv%VA!?5O=-%uN>UwqG>$LwDqLhB6\`Zm.zVaб[KiGV%Ic啲Ő-6Z,b'uZmPua@%%~Lo` .c&ua4^h EW,A muq~],&mBB2/*v|)󶊻tOoC3ZGeGt*k)9ɭ$HYz2э4fDf9PΓ0nIPC'nUꁣL;|T jt9n`}unۜbk%՞it'?mp2D$ؚ!:zoA>D-t Q_uiv vbA1[DQsqaT{S$f3wtr YUcʯ^yܕ=nS>]o rǹ=Arr,Nns};d414lPE`wn}Trkc0s9k;G![|yfY Z~ҳmiŜ4^h@Wq 4N9SֵocgZዞBu<2r3OgnU&tZ8!{o|HhOI> A9=iӊ~g;+,^[{5ǜ TlcFѭ{&P>EIpp .B/?-U.TΥG fa+f1lV19pBxH WXP xR{ݞ|OOOrIϮw5m-v);sL)Y>]EۢE&`}ji(k,\-=#hLߕ&mqz541ڞZF!ahy>e27 qf@,FR Ͳ[­}VumnǾW_( ?;/<=^'_CnU.Z TK( lcV>.V[֏<:[?ʟŝ>LП=m(-͋g^'tC0yc'*KI}l q5ev6Sl;s]d@yE_+4( N*E 55&h[j8(/Kh &Z5x @g~H\E'\#{U ppj'G8ڙaBR<F `%>}7~ woީΦ5a}2܆OaRg D<^\ɀTe9ΰ[:HA,mkG ;Ϟ߯I 2O\TiK+VϹ  B_6$-RDt:YgPި k@u_0: sm~s7Et=%F=%F<ؾkf^^\(G,lHfuIs %X95++Qk,f3F@dWX4}~Kd5{JdϷ"{~VU7"1bDw tfs|Vc$m+^ӒK8[AVtgm|yٞ,M! F2'@bDe ZV oCwXgPG֪l$5 nX<ѣqiOupGI5Y -Wܭl%4~mlSiA 6" YV7Vz_}? {/WB?Ko^l60h?6'h05RfrmRBߑGu%iٛO[AwOlm{v5L%@p\}ak5w+%H\]UσG[6D2][qF(kGɽM~韾C{)}y Ӷv^h lk#XhA/=\k?cNnr[mclmSX{KhBU'@&Їo}q L^ 1lבuvKr*hŅK%?N8fxıՄK B}<<'^g'^'v~VSTޖ2H|0!)v6jd'&OnzVy Pٶ I1_hPOTw3 b9Mun☫hcaZG %uY5zfDcfIDJa|g^'jyq aVp5}9]{~ ?*rԲl k7wAkڎb.'Yfu@aJϢ- Bl{#6 !2~zptVtI_![ASսk$h:Ztdx6(@ avT'v$k%xߣƿ|_7~-S̥ Ut[ &^^Ҝu6v4w'*GdF4\Z!\3pݛzP_}2kڟ~_Etb < ֘F+rDV:pt4_~?H/(DhZys9c߾&-}p|RI` e+g٠XڂkmmߔشbN vcPŏ-cڱ_%4:8v@_^K΀m8B2νwS10q =u@0$#Hi.4rم'5◳!@'|HlrSnQjhfr sEG*s>GV!5ĥ Qy[DZs_x Oɷ7_}W_Ϳ/WIPi9[z.żki6-; MޡaYOzv!j*^mi,VQ7g @8T/DHLUuݾ7 Px#)ӎ"9F qrQ4؋dS91uǀ.O}s6s {=C2T|DLr:Sތ5*)HpW h uE$sd[֏z"Lq4W?cB%~S$@6Bɞn&rti;."xεx d "A!XsCz}5 %ITx/[Lߘ 5{x )cm[zz6uq=Mf!pJCbmg`vӁD̤I?;+<)y陣v >FfȌ5 2Y˅DHDSEg6hTֹ[1dD>E<* LoN[qX9a@N5;f ̵vh ^Fn%$p^{ g,2ۥ()/]\YJkmҒ),:Gq[@'īȶ5B!'ۛ5@X, ytI576!t5u(*81*8/"cҦ0^{k*t,lhcC6[y>7'V {Iʋc%!o:of_ҪC)|CF|Ҟl6ø2U/96Nԝvd>l-Htz_ |CzxTڵXcVl-(2Sڼʻ8- 'pxf\{B6 T^D#V;a&Sofzrސ;ۘxJْ '_wu6?^O+Kt(se+\=ϱ "J$9k\;AKZII\~ZHz[ki_=24\PntN{t-RC/:2;#v$Z;kどU?mXd{(pًs4(s/1 ҵ[Xړ {;NHUE. C%My?)뽿WJ|z߫*7ޕ~/]^5 O==dG.4`WbeGzOvA]a zH[?IЉT¬51QLu>OXcZ8;,5|g{)qU馎=K,Y+iDi^q{¥Ҕ ϙgZo9h~_7/x곗oj?wZ?QoWW 񥔭1RF Z?2 5Mؐq\J:Il{i;ٜ4W#uDvW*BPl1 CNu"1a㬎phfuܥLWE' 9w+?3SΗlCD$ՌvLD s&^1c(eнFMiPr4M*f/hPֶ?7Ι#%ӋeȤ2VNL}= _3ޑ(֬N'jg` $y?lNl"'bg}TjPcy p|Ś&ה C ٗ#Rz؆_\?7M2ކvaq p-q4A"hnm+B=rG0NQg]"Ό U)F]H xteZإ` 6ʎə} zo{p0ٛBگUi(r'BgvB8Q;Oչ$0`6^&~T΁mŁ]Yfn %fҟ蔋&ܝ~W_"W߸1EbVoMO!B SdŕWoLrzEMf \6nSEWk 9V}jS1xFÿyEyhw7MI6 /c^Jc4v|`* ݨ  EKH?."WkQ r 0wΕE2/ n*!=c2zC 7F@K&nkگqRK>oׂpVIH+A0U)Vj5&\(@Ds_g!@ lRV|&7W.d5N%Y+f-1gupGRP7f)F텚3 >N::^u:uOb<=PiflËz2xM<ѕ;E]a2?s['\ x 6ôQǫEKJ S ٛ>Zp6F=u3x)!HM f[)!Dl$sF4Ǫ4>ز F7Z)bAN?U Y7qUlF9x "' 'C)$CIݤV&Xw\()f]^j KR~6 VښFuP$Kyj×=vNSb4$"HpΞ-1[G ?S9Hx."thF\d GBָ!G%2=BH(Ǧ8W?hiۈ$J>jß"&18=|sKfEBLb ܞ!jUL}pr2&.#u\:m*YpŔp4aFldĝC6su`)^ļ YN"3ڻI (4x⡲*ʣ/!'wfvٻx!1|<^x>Yyߖ[U]:  .꭪d@\&Jl4^ Nݩc&wV.Lb}6zMl7⚻(w9V^ۃr}8oSƺpKR/ UKj)uhS|w%+$;jSD#Yup5Dhծ>jt5v[j0'>[p;n% D52dIé ,R%pvﻵJs,o:1ZHD5jR:(7*n![pET_/Q}%v~wZ/>|L(6/՟˧w>{hyr֎_>tVSFZ v\B8g)D ghP,.95 {_B.u}p&[s3qPРXNNGÇ{>o|s?>f ,/ lreplace-in-file-main/.yarnrc.yml000066400000000000000000000000311511441262100170220ustar00rootroot00000000000000nodeLinker: node-modules replace-in-file-main/CHANGELOG.md000066400000000000000000000064111511441262100165440ustar00rootroot00000000000000## 8.0.0 The package has been converted to an ES module and now requires Node 18 or higher. If you need support for Node 16 or below, please use version 7.x.x. ### Breaking changes - Package has been converted to an ES module - No longer providing a default export. Use the named exports `replaceInFile` or `replaceInFileSync` instead. - The `replace.sync` syntax is no longer available. Use the named export `replaceInFileSync` instead. - The callback API has been removed for asynchronous replacements. Please use promises or `async/await` instead. - Configuration files provided to the CLI using the `--configFile` flag can now only be JSON. - To use a custom `fs` implementation, you must now specify `fs` config parameter for the async API, and `fsSync` for the sync API. For the asynchronous APIs, the provided `fs` must provide the `readFile` and `writeFile` methods. For the synchronous APIs, the provided `fsSync` must provide the `readFileSync` and `writeFileSync` methods. - If a `cwd` parameter is provided, it will no longer be prefixed to each path using basic string concatenation, but rather uses `path.join()` to ensure correct path concatenation. ### New features - The `isRegex` flag is no longer required. - You can now specify a `getTargetFile` config param to modify the target file for saving the new file contents to. For example: ```js const options = { files: 'path/to/files/*.html', getTargetFile: source => `new/path/${source}`, from: 'foo', to: 'bar', } ``` ## 7.0.0 Strings provided to the `from` value are now escaped for regex matching when counting of matches is enabled. This is unlikely to result in any breaking changes, but as a precaution the major version has been bumped. ## 6.0.0 From version 6.0.0 onwards, replace in file requires Node 10 or higher. If you need support for Node 8, please use version 5.x.x. ## 5.0.0 From version 5.0.0 onwards, replace in file requires Node 8 or higher. If you need support for Node 6, please use version 4.x.x. ## 4.0.0 ### Breaking changes The return value is now a results array instead of an array with changed files. The new results array includes each file that was processed, with a flag to indicate whether or not the file was changed, and optionally information about the number of matches and replacements that were made. See the readme for more details. To update existing code and obtain an array of changed files again, simply convert the results array as follows: ```js const results = await replace(options); const changedFiles = results .filter(result => result.hasChanged) .map(result => result.file); ``` ### New features - Added `countMatches` flag to count the number of matches and replacements per file [#38](https://github.com/adamreisnz/replace-in-file/issues/38), [#42](https://github.com/adamreisnz/replace-in-file/issues/42), [#61](https://github.com/adamreisnz/replace-in-file/issues/61) - Added `--quiet` flag for CLI to suppress success output [#63](https://github.com/adamreisnz/replace-in-file/issues/63) - Added `cwd` configuration parameter for network drive replacements [#56](https://github.com/adamreisnz/replace-in-file/issues/56) ## 3.0.0 ### Breaking changes From version 3.0.0 onwards, replace in file requires Node 6 or higher. If you need support for Node 4 or 5, please use version 2.x.x. replace-in-file-main/README.md000066400000000000000000000402111511441262100162060ustar00rootroot00000000000000# Replace in file [![npm version](https://img.shields.io/npm/v/replace-in-file.svg)](https://www.npmjs.com/package/replace-in-file) [![coverage status](https://coveralls.io/repos/github/adamreisnz/replace-in-file/badge.svg?branch=master)](https://coveralls.io/github/adamreisnz/replace-in-file?branch=master) [![github issues](https://img.shields.io/github/issues/adamreisnz/replace-in-file.svg)](https://github.com/adamreisnz/replace-in-file/issues) A simple utility to quickly replace text in one or more files or globs. Works synchronously or asynchronously with either promises or callbacks. Make a single replacement or multiple replacements at once. ## Index - [Installation](#installation) - [Basic usage](#basic-usage) - [Asynchronous replacement](#asynchronous-replacement) - [Synchronous replacement](#synchronous-replacement) - [Return value](#return-value) - [Counting matches and replacements](#counting-matches-and-replacements) - [Advanced usage](#advanced-usage) - [Replace a single file or glob](#replace-a-single-file-or-glob) - [Replace multiple files or globs](#replace-multiple-files-or-globs) - [Replace first occurrence only](#replace-first-occurrence-only) - [Replace all occurrences](#replace-all-occurrences) - [Multiple values with the same replacement](#multiple-values-with-the-same-replacement) - [Custom regular expressions](#custom-regular-expressions) - [Multiple values with different replacements](#multiple-values-with-different-replacements) - [Multiple replacements with different options](#multiple-replacements-with-different-options) - [Using callbacks for `from`](#using-callbacks-for-from) - [Using callbacks for `to`](#using-callbacks-for-to) - [Saving to a different file](#saving-to-a-different-file) - [Ignore a single file or glob](#ignore-a-single-file-or-glob) - [Ignore multiple files or globs](#ignore-multiple-files-or-globs) - [Allow empty/invalid paths](#allow-emptyinvalid-paths) - [Disable globs](#disable-globs) - [Specify glob configuration](#specify-glob-configuration) - [Making replacements on network drives](#making-replacements-on-network-drives) - [Specify character encoding](#specify-character-encoding) - [Dry run](#dry-run) - [Using custom processors](#using-custom-processors) - [Using a custom file system API](#using-a-custom-file-system-api) - [CLI usage](#cli-usage) - [A note on using globs with the CLI](#a-note-on-using-globs-with-the-cli) - [Version information](#version-information) - [License](#license) ## Installation ```shell # Using npm npm i replace-in-file # Using yarn yarn add replace-in-file ``` ### Asynchronous replacement ```js import {replaceInFile} from 'replace-in-file' const options = { files: 'path/to/file', from: /foo/g, to: 'bar', } try { const results = await replaceInFile(options) console.log('Replacement results:', results) } catch (error) { console.error('Error occurred:', error) } ``` ### Synchronous replacement ```js import {replaceInFileSync} from 'replace-in-file' const options = { files: 'path/to/file', from: /foo/g, to: 'bar', } try { const results = replaceInFileSync(options) console.log('Replacement results:', results) } catch (error) { console.error('Error occurred:', error) } ``` ### Return value The return value of the library is an array of replacement results against each file that was processed. This includes files in which no replacements were made. Each result contains the following values: - `file`: The path to the file that was processed - `hasChanged`: Flag to indicate if the file was changed or not ```js const results = replaceInFileSync({ files: 'path/to/files/*.html', from: /foo/g, to: 'bar', }) console.log(results) // [ // { // file: 'path/to/files/file1.html', // hasChanged: true, // }, // { // file: 'path/to/files/file2.html', // hasChanged: true, // }, // { // file: 'path/to/files/file3.html', // hasChanged: false, // }, // ] ``` To get an array of changed files, simply map the results as follows: ```js const changedFiles = results .filter(result => result.hasChanged) .map(result => result.file) ``` ### Counting matches and replacements By setting the `countMatches` configuration flag to `true`, the number of matches and replacements per file will be counted and present in the results array. - `numMatches`: Indicates the number of times a match was found in the file - `numReplacements`: Indicates the number of times a replacement was made in the file Note that the number of matches can be higher than the number of replacements if a match and replacement are the same string. ```js const results = replaceInFileSync({ files: 'path/to/files/*.html', from: /foo/g, to: 'bar', countMatches: true, }) console.log(results) // [ // { // file: 'path/to/files/file1.html', // hasChanged: true, // numMatches: 3, // numReplacements: 3, // }, // { // file: 'path/to/files/file2.html', // hasChanged: true, // numMatches: 1, // numReplacements: 1, // }, // { // file: 'path/to/files/file3.html', // hasChanged: false, // numMatches: 0, // numReplacements: 0, // }, // ] ``` ## Advanced usage ### Replace a single file or glob ```js const options = { files: 'path/to/file', } ``` ### Replace multiple files or globs ```js const options = { files: [ 'path/to/file', 'path/to/other/file', 'path/to/files/*.html', 'another/**/*.path', ], } ``` ### Replace first occurrence only ```js const options = { from: 'foo', to: 'bar', } ``` ### Replace all occurrences Please note that the value specified in the `from` parameter is passed straight to the native [String replace method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace). As such, if you pass a string as the `from` parameter, it will _only replace the first occurrence_. To replace multiple occurrences at once, you must use a regular expression for the `from` parameter with the global flag enabled, e.g. `/foo/g`. ```js const options = { from: /foo/g, to: 'bar', } ``` ### Multiple values with the same replacement These will be replaced sequentially. ```js const options = { from: [/foo/g, /baz/g], to: 'bar', } ``` ### Multiple values with different replacements These will be replaced sequentially. ```js const options = { from: [/foo/g, /baz/g], to: ['bar', 'bax'], } ``` ### Multiple replacements with different options There is no direct API in this package to make multiple replacements on different files with different options. However, you can easily accomplish this in your scripts as follows: ```js const replacements = [ { files: 'path/to/file1', from: /foo/g, to: 'bar', }, { files: 'path/to/file2', from: /bar/g, to: 'foo', } ] await Promise.all( replacements.map(options => replaceInFile(options)) ) ``` ### Custom regular expressions Use the [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) constructor to create any regular expression. ```js const str = 'foo' const regex = new RegExp('^' + str + 'bar', 'i') const options = { from: regex, to: 'bar', } ``` ### Using callbacks for `from` You can also specify a callback that returns a string or a regular expression. The callback receives the name of the file in which the replacement is being performed, thereby allowing the user to tailor the search string. The following example uses a callback to produce a search string dependent on the filename: ```js const options = { files: 'path/to/file', from: (file) => new RegExp(file, 'g'), to: 'bar', } ``` ### Using callbacks for `to` As the `to` parameter is passed to the native [String replace method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace), you can also specify a callback. The following example uses a callback to convert matching strings to lowercase: ```js const options = { files: 'path/to/file', from: /SomePattern[A-Za-z-]+/g, to: (match) => match.toLowerCase(), } ``` This callback provides for an extra argument above the String replace method, which is the name of the file in which the replacement is being performed. The following example replaces the matched string with the filename: ```js const options = { files: 'path/to/file', from: /SomePattern[A-Za-z-]+/g, to: (...args) => args.pop(), } ``` ### Saving to a different file You can specify a `getTargetFile` config param to modify the target file for saving the new file contents to. For example: ```js const options = { files: 'path/to/files/*.html', getTargetFile: source => `new/path/${source}`, from: 'foo', to: 'bar', } ``` ### Ignore a single file or glob ```js const options = { ignore: 'path/to/ignored/file', } ``` ### Ignore multiple files or globs ```js const options = { ignore: [ 'path/to/ignored/file', 'path/to/other/ignored_file', 'path/to/ignored_files/*.html', 'another/**/*.ignore', ], } ``` Please note that there is an [open issue with Glob](https://github.com/isaacs/node-glob/issues/309) that causes ignored patterns to be ignored when using a `./` prefix in your files glob. To work around this, simply remove the prefix, e.g. use `**/*` instead of `./**/*`. ### Allow empty/invalid paths If set to true, empty or invalid paths will fail silently and no error will be thrown. For asynchronous replacement only. Defaults to `false`. ```js const options = { allowEmptyPaths: true, } ``` ### Disable globs You can disable globs if needed using this flag. Use this when you run into issues with file paths like files like `//SERVER/share/file.txt`. Defaults to `false`. ```js const options = { disableGlobs: true, } ``` ### Specify glob configuration Specify configuration passed to the [glob](https://www.npmjs.com/package/glob) call: ```js const options = { //Glob settings here (examples given below) glob: { //To include hidden files (starting with a dot) dot: true, //To fix paths on Windows OS when path.join() is used to create paths windowsPathsNoEscape: true, }, } ``` Please note that the setting `nodir` will always be passed as `false`. ### Making replacements on network drives To make replacements in files on network drives, you may need to specify the UNC path as the `cwd` config option. This will then be passed to glob and prefixed to your paths accordingly. See [#56](https://github.com/adamreisnz/replace-in-file/issues/56) for more details. ### Specify character encoding Use a different character encoding for reading/writing files. Defaults to `utf-8`. ```js const options = { encoding: 'utf8', } ``` ### Dry run To do a dry run without actually making replacements, for testing purposes. Defaults to `false`. ```js const options = { dry: true, } ``` ### Using custom processors For advanced usage where complex processing is needed it's possible to use a callback that will receive content as an argument and should return it processed. ```js const results = await replaceInFile({ files: 'path/to/files/*.html', processor: (input) => input.replace(/foo/g, 'bar'), }) ``` The custom processor will receive the path of the file being processed as a second parameter: ```js const results = await replaceInFile({ files: 'path/to/files/*.html', processor: (input, file) => input.replace(/foo/g, file), }) ``` This also supports passing an array of functions that will be executed sequentially ```js function someProcessingA(input) { const chapters = input.split('###') chapters[1] = chapters[1].replace(/foo/g, 'bar') return chapters.join('###') } function someProcessingB(input) { return input.replace(/foo/g, 'bar') } const results = replaceInFileSync({ files: 'path/to/files/*.html', processor: [someProcessingA, someProcessingB], }) ``` Alongside the `processor`, there is also `processorAsync` which is the equivalent for asynchronous processing. It should return a promise that resolves with the processed content: ```js const results = await replaceInFile({ files: 'path/to/files/*.html', processorAsync: async (input, file) => { const asyncResult = await doAsyncOperation(input, file); return input.replace(/foo/g, asyncResult) }, }) ``` ### Using a custom file system API `replace-in-file` defaults to using `'node:fs/promises'` and `'node:fs'` to provide file reading and write APIs. You can provide an `fs` or `fsSync` object of your own to switch to a different file system, such as a mock file system for unit tests. * For the asynchronous APIs, the provided `fs` must provide the `readFile` and `writeFile` methods. * For the synchronous APIs, the provided `fsSync` must provide the `readFileSync` and `writeFileSync` methods. Custom `fs` and `fsSync` implementations should have the same parameters and returned values as their [built-in Node `fs`](https://nodejs.org/api/fs.html) equivalents. ```js replaceInFile({ from: 'a', fs: { readFile: async (file, encoding) => { console.log(`Reading ${file} with encoding ${encoding}...`) return 'fake file contents' }, writeFile: async (file, newContents, encoding) => { console.log(`Writing ${file} with encoding ${encoding}: ${newContents}`) }, }, to: 'b', }) ``` Or for the sync API: ```js replaceInFileSync({ from: 'a', fsSync: { readFileSync: (file, encoding) => { console.log(`Reading ${file} with encoding ${encoding}...`) return 'fake file contents' }, writeFileSync: (file, newContents, encoding) => { console.log(`Writing ${file} with encoding ${encoding}: ${newContents}`) }, }, to: 'b', }) ``` ## CLI usage ```sh replace-in-file from to some/file.js,some/**/glob.js [--configFile=config.json] [--ignore=ignore/files.js,ignore/**/glob.js] [--encoding=utf-8] [--disableGlobs] [--verbose] [--quiet] [--dry] ``` Multiple files or globs can be replaced by providing a comma separated list. The flags `--disableGlobs`, `--ignore` and `--encoding` are supported in the CLI. The setting `allowEmptyPaths` is not supported in the CLI as the replacement is synchronous, and this setting is only relevant for asynchronous replacement. To list the changed files, use the `--verbose` flag. Success output can be suppressed by using the `--quiet` flag. To do a dry run without making any actual changes, use `--dry`. A regular expression may be used for the `from` parameter by passing in a string correctly formatted as a regular expression. The library will automatically detect that it is a regular expression. The `from` and `to` parameters, as well as the files list, can be omitted if you provide this information in a configuration file. You can provide a path to a configuration file (JSON) with the `--configFile` flag. This path will be resolved using Node’s built in `path.resolve()`, so you can pass in an absolute or relative path. If you are using a configuration file, and you want to use a regular expression for the `from` value, ensure that it starts with a `/`, for example: ```json { "from": "/cat/g", "to": "dog", } ``` ## A note on using globs with the CLI When using the CLI, the glob pattern is handled by the operating system. But if you specify the glob pattern in the configuration file, the package will use the glob module from the Node modules, and this can lead to different behaviour despite using the same pattern. For example, the following will only look at top level files: ```json { "from": "cat", "to": "dog", } ``` ```sh replace-in-file ** --configFile=config.json ``` However, this example is recursive: ```json { "files": "**", "from": "cat", "to": "dog", } ``` ```sh replace-in-file --configFile=config.json ``` If you want to do a recursive file search as an argument you must use: ```sh replace-in-file $(ls l {,**/}*) --configFile=config.json ``` ## Version information From version 8.0.0 onwards, this package requires Node 18 or higher. If you need support for older versions of Node, please use a previous version of this package. As 8.0.0 was a significant rewrite, please [open an issue](https://github.com/adamreisnz/replace-in-file/issues) if you run into any problems or unexpected behaviour. See the [Changelog](CHANGELOG.md) for more information. ## License (MIT License) Copyright 2015-2024, Adam Reis replace-in-file-main/bin/000077500000000000000000000000001511441262100155015ustar00rootroot00000000000000replace-in-file-main/bin/cli.js000077500000000000000000000033451511441262100166160ustar00rootroot00000000000000#!/usr/bin/env node import yargs from 'yargs' import {hideBin} from 'yargs/helpers' import {replaceInFileSync} from '../src/replace-in-file.js' import {loadConfig, combineConfig} from '../src/helpers/config.js' import {errorHandler, successHandler} from '../src/helpers/handlers.js' /** * Main routine */ async function main() { //Extract parameters const argv = yargs(hideBin(process.argv)).argv const {configFile} = argv //Display help if (argv.help || argv.h) { return console.log(` Usage: replace-in-file from to from to some/file.js,some/**/glob.js Available options (all are optional): --configFile Path to JSON config file --ignore Files to ignore (comma separated) --encoding File encoding (default is utf-8) --disableGlobs Disable glob expansion --verbose Show additional information --quiet Suppress output --dry Dry run (no changes made) --help, -h Show this help information `) } //Verify arguments if (argv._.length < 3 && !configFile) { throw new Error('Replace in file needs at least 3 arguments') } //Load config and combine with passed arguments const config = configFile ? await loadConfig(configFile) : {} const options = combineConfig(config, argv) //Extract settings const {from, to, files, verbose, quiet} = options //Single star globs already get expanded in the command line options.files = files.reduce((files, file) => { return files.concat(file.split(',')) }, []) //Log if (!quiet) { console.log(`Replacing '${from}' with '${to}'`) } //Replace const results = replaceInFileSync(options) if (!quiet) { successHandler(results, verbose) } } //Call main routine main().catch(error => errorHandler(error)) replace-in-file-main/eslint.config.js000066400000000000000000000031631511441262100200340ustar00rootroot00000000000000import js from '@eslint/js' import globals from 'globals' export default [ js.configs.recommended, { ignores: [ 'node_modules', 'coverage', ], languageOptions: { ecmaVersion: 'latest', sourceType: 'module', globals: { ...globals.builtin, ...globals.node, ...globals.mocha, ...globals.jasmine, }, }, rules: { indent: ['error', 2, { SwitchCase: 1, }], quotes: ['error', 'single', { allowTemplateLiterals: true, }], 'brace-style': ['error', 'stroustrup', { allowSingleLine: false, }], curly: 'error', 'comma-dangle': ['error', { functions: 'never', arrays: 'always-multiline', objects: 'always-multiline', }], 'space-infix-ops': ['error'], 'quote-props': ['error', 'as-needed'], 'object-curly-spacing': ['error', 'never'], 'space-before-blocks': 'error', 'keyword-spacing': 'error', semi: ['error', 'never'], 'eol-last': ['error', 'always'], 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-empty': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 'no-empty-function': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 'no-unused-vars': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 'no-unreachable': process.env.NODE_ENV === 'production' ? 'error' : 'warn', 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0, }], }, }, ] replace-in-file-main/index.js000066400000000000000000000003371511441262100164010ustar00rootroot00000000000000import {replaceInFile, replaceInFileSync} from './src/replace-in-file.js' import {processFile, processFileSync} from './src/process-file.js' //Export export {replaceInFile, replaceInFileSync, processFile, processFileSync} replace-in-file-main/package.json000066400000000000000000000024071511441262100172220ustar00rootroot00000000000000{ "name": "replace-in-file", "type": "module", "version": "8.4.0", "description": "A simple utility to quickly replace text in one or more files.", "homepage": "https://github.com/adamreisnz/replace-in-file#readme", "author": { "name": "Adam Reis", "email": "adam@reis.nz" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/adamreisnz/replace-in-file.git" }, "bugs": { "url": "https://github.com/adamreisnz/replace-in-file/issues" }, "keywords": [ "replace", "text", "contents", "file" ], "main": "index.js", "bin": "./bin/cli.js", "types": "./types/index.d.ts", "engines": { "node": ">=18" }, "scripts": { "test": "mocha 'src/**/*.spec.js'", "coverage": "c8 npm run test", "postcoverage": "open -a \"Google Chrome\" ./coverage/lcov-report/index.html", "postversion": "git push && git push --tags && npm publish" }, "files": [ "bin", "src", "types", "index.js" ], "dependencies": { "chalk": "^5.6.2", "glob": "^13.0.0", "yargs": "^18.0.0" }, "devDependencies": { "@eslint/js": "^9.39.1", "c8": "^10.1.3", "chai": "^6.2.1", "chai-as-promised": "^8.0.2", "eslint": "^9.39.1", "mocha": "^11.7.5" } } replace-in-file-main/src/000077500000000000000000000000001511441262100155205ustar00rootroot00000000000000replace-in-file-main/src/helpers/000077500000000000000000000000001511441262100171625ustar00rootroot00000000000000replace-in-file-main/src/helpers/config.js000066400000000000000000000103761511441262100207740ustar00rootroot00000000000000import path from 'node:path' import fs from 'node:fs/promises' import fsSync from 'node:fs' /** * Helper to load options from a config file */ export async function loadConfig(file) { //No config file provided? if (!file) { throw new Error(`No config file provided`) } //Read file const json = await fs.readFile(path.resolve(file), 'utf8') return JSON.parse(json) } /** * Helper to convert a string to Regex if it matches the pattern */ export function stringToRegex(str) { //Array given if (Array.isArray(str)) { return str.map(stringToRegex) } //Not a string, or no match const regexMatch = /.*\/([gimyus]*)$/ if (typeof str !== 'string' || !str.match(regexMatch)) { return str } //Extract flags and pattern const flags = str.replace(/.*\/([gimyus]*)$/, '$1') const pattern = str.replace(new RegExp(`^/(.*?)/${flags}$`), '$1') //Return regex return new RegExp(pattern, flags) } /** * Parse config */ export function parseConfig(config) { //Validate config if (typeof config !== 'object' || config === null) { throw new Error('Must specify configuration object') } //Fix glob config.glob = config.glob || {} //Extract data const {files, getTargetFile, from, to, processor, processorAsync, ignore, encoding} = config if (typeof processor !== 'undefined') { if (typeof processor !== 'function' && !Array.isArray(processor)) { throw new Error(`Processor should be either a function or an array of functions`) } } else if (typeof processorAsync !== 'undefined') { if (typeof processorAsync !== 'function' && !Array.isArray(processorAsync)) { throw new Error(`ProcessorAsync should be either a function or an array of functions`) } } else { if (typeof files === 'undefined') { throw new Error('Must specify file or files') } if (typeof from === 'undefined') { throw new Error('Must specify string or regex to replace') } if (typeof to === 'undefined') { throw new Error('Must specify a replacement (can be blank string)') } if (typeof getTargetFile !== 'undefined' && typeof getTargetFile !== 'function') { throw new Error(`Target file transformation parameter should be a function that takes the source file path as argument and returns the target file path`) } } //Ensure arrays if (!Array.isArray(files)) { config.files = [files] } if (!Array.isArray(ignore)) { if (typeof ignore === 'undefined') { config.ignore = [] } else { config.ignore = [ignore] } } //Since we can't store Regexp in JSON, convert from string if needed config.from = stringToRegex(from) //Use default encoding if invalid if (typeof encoding !== 'string' || encoding === '') { config.encoding = 'utf-8' } //Merge config with defaults return Object.assign({}, { ignore: [], encoding: 'utf-8', disableGlobs: false, allowEmptyPaths: false, countMatches: false, verbose: false, quiet: false, dry: false, glob: {}, cwd: null, getTargetFile: source => source, fs, fsSync, }, config) } /** * Combine CLI script arguments with config options */ export function combineConfig(config, argv) { //Extract options from config let { from, to, files, ignore, encoding, verbose, allowEmptyPaths, disableGlobs, dry, quiet, } = config //Get from/to parameters from CLI args if not defined in options if (typeof from === 'undefined') { from = argv._.shift() } if (typeof to === 'undefined') { to = argv._.shift() } //Get files and ignored files if (typeof files === 'undefined') { files = argv._ } if (typeof ignore === 'undefined' && typeof argv.ignore !== 'undefined') { ignore = argv.ignore } //Other parameters if (typeof encoding === 'undefined') { encoding = argv.encoding } if (typeof disableGlobs === 'undefined') { disableGlobs = !!argv.disableGlobs } if (typeof verbose === 'undefined') { verbose = !!argv.verbose } if (typeof dry === 'undefined') { dry = !!argv.dry } if (typeof quiet === 'undefined') { quiet = !!argv.quiet } //Return through parser to validate return parseConfig({ from, to, files, ignore, encoding, verbose, allowEmptyPaths, disableGlobs, dry, quiet, }) } replace-in-file-main/src/helpers/config.spec.js000066400000000000000000000157671511441262100217360ustar00rootroot00000000000000import {expect, use, should} from 'chai' import chaiAsPromised from 'chai-as-promised' import {loadConfig, combineConfig, parseConfig} from './config.js' import fs from 'node:fs' //Enable should assertion style for usage with chai-as-promised should() use(chaiAsPromised) /** * Specs */ describe('helpers/config.js', () => { /** * Load config */ describe('loadConfig()', () => { it('should error if no file is provided', () => { return expect(loadConfig()).to.eventually.be.rejectedWith(Error) }) it('should error when an invalid file is provided', () => { return expect(loadConfig(42)).to.eventually.be.rejectedWith(Error) }) it('should read config from a valid file', async () => { //Test config const config = { files: ['file.txt'], from: 'foo', to: 'bar', } fs.writeFileSync('config.json', JSON.stringify(config), 'utf8') //Load config const cfg = await loadConfig('config.json') expect(cfg).to.be.an('object') expect(cfg.files).to.be.an('array') expect(cfg.files).to.eql(config.files) expect(cfg.from).to.equal(config.from) expect(cfg.to).to.equal(config.to) //Clean up fs.unlinkSync('config.json') }) }) /** * Combine config */ describe('combineConfig()', () => { it('should combine config with passed arguments', () => { const argv = { _: ['foo', 'bar', 'file.txt'], ignore: ['ignore-file.txt'], encoding: 'encoding', disableGlobs: true, dry: true, quiet: true, } const combined = combineConfig({}, argv) expect(combined.from).to.equal('foo') expect(combined.to).to.equal('bar') expect(combined.files).to.eql(['file.txt']) expect(combined.ignore).to.eql(['ignore-file.txt']) expect(combined.encoding).to.equal('encoding') expect(combined.disableGlobs).to.be.true expect(combined.dry).to.be.true expect(combined.quiet).to.be.true }) }) /** * Parse config */ describe('parseConfig()', () => { it('should error if no config is provided', () => { expect(() => parseConfig()).to.throw(Error) }) it('should error when an invalid config is provided', () => { expect(() => parseConfig(42)).to.throw(Error) expect(() => parseConfig(null)).to.throw(Error) }) it('should error when an invalid `processor` is specified', () => { expect(() => parseConfig({ processor: 'foo', files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b'], })).to.throw(Error) }) it('should error when an invalid `processorAsync` is specified', () => { expect(() => parseConfig({ processorAsync: 'foo', files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b'], })).to.throw(Error) }) it('should error when `files` are not specified', () => { expect(() => parseConfig({ from: [/re/g, /place/g], to: ['b'], })).to.throw(Error) }) it('should error when `from` is not specified', () => { expect(() => parseConfig({ files: ['test1', 'test2', 'test3'], to: ['b'], })).to.throw(Error) }) it('should error when `to` is not specified', () => { expect(() => parseConfig({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], })).to.throw(Error) }) it('should error when an invalid `getTargetFile` handler is specified', () => { expect(() => parseConfig({ getTargetFile: 'foo', files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b'], })).to.throw(Error) }) it('should convert `files` to an array', () => { const parsed = parseConfig({ files: 'test1', from: [/re/g, /place/g], to: ['b'], }) expect(parsed.files).to.eql(['test1']) }) it('should default the `ignore` option to an empty array', () => { const parsed = parseConfig({ files: ['test1'], from: [/re/g, /place/g], to: ['b'], }) expect(parsed.ignore).to.eql([]) }) it('should convert the `ignore` option to an array', () => { const parsed = parseConfig({ files: ['test1'], from: [/re/g, /place/g], to: ['b'], ignore: 'ignore-file.txt', }) expect(parsed.ignore).to.eql(['ignore-file.txt']) }) it('should default `encoding` to utf-8 if not provided or invalid', () => { const a = parseConfig({ files: ['test1'], from: [/re/g, /place/g], to: ['b'], }) const b = parseConfig({ files: ['test1'], from: [/re/g, /place/g], to: ['b'], encoding: 42, }) const c = parseConfig({ files: ['test1'], from: [/re/g, /place/g], to: ['b'], encoding: '', }) expect(a.encoding).to.equal('utf-8') expect(b.encoding).to.equal('utf-8') expect(c.encoding).to.equal('utf-8') }) it('should convert from regex if provided in JSON', async () => { const parsed = parseConfig({ files: ['file.txt'], from: '/foo/g', to: 'bar', }) expect(parsed.from).to.be.an.instanceof(RegExp) }) it('should convert from an array of regexes if provided in JSON', async () => { const parsed = parseConfig({ files: ['file.txt'], from: ['/foo/g', '/baz/g', 'plain'], to: 'bar', }) expect(parsed.from).to.be.an.instanceof(Array) expect(parsed.from[0]).to.be.an.instanceof(RegExp) expect(parsed.from[1]).to.be.an.instanceof(RegExp) expect(parsed.from[2]).to.equal('plain') }) it('should not convert from regex if it is a regular string', async () => { const parsed = parseConfig({ files: ['file.txt'], from: '/foo', to: 'bar', }) expect(parsed.from).not.to.be.an.instanceof(RegExp) expect(parsed.from).to.equal('/foo') }) it('should overwrite the config defaults', () => { const parsed = parseConfig({ files: 'test1', from: [/re/g, /place/g], to: ['b'], ignore: 'ignore-file.txt', encoding: 'encoding', disableGlobs: true, allowEmptyPaths: true, countMatches: true, verbose: true, quiet: true, dry: true, glob: 'glob', cwd: 'cwd', fs: 'fs', fsSync: 'fsSync', }) expect(parsed.ignore).to.eql(['ignore-file.txt']) expect(parsed.encoding).to.equal('encoding') expect(parsed.disableGlobs).to.be.true expect(parsed.allowEmptyPaths).to.be.true expect(parsed.countMatches).to.be.true expect(parsed.verbose).to.be.true expect(parsed.quiet).to.be.true expect(parsed.dry).to.be.true expect(parsed.glob).to.equal('glob') expect(parsed.cwd).to.equal('cwd') expect(parsed.fs).to.equal('fs') expect(parsed.fsSync).to.equal('fsSync') }) }) }) replace-in-file-main/src/helpers/handlers.js000066400000000000000000000013601511441262100213200ustar00rootroot00000000000000import chalk from 'chalk' /** * Success handler */ export function successHandler(results, verbose) { const changed = results.filter(result => result.hasChanged) const numChanges = changed.length if (numChanges > 0) { console.log(chalk.green(`${numChanges} file(s) were changed`)) if (verbose) { changed.forEach(result => console.log(chalk.grey('-', result.file))) } } else { console.log(chalk.yellow('No files were changed')) } } /** * Error handler */ export function errorHandler(error, exitCode = 1) { console.error(error) process.exit(exitCode) } /** * Helper to log a dry run */ export function logDryRun(log) { if (log) { console.log(chalk.yellow('Dry run, not making actual changes')) } } replace-in-file-main/src/helpers/paths.js000066400000000000000000000032371511441262100206440ustar00rootroot00000000000000import {glob} from 'glob' import nodepath from 'node:path' /** * Async wrapper for glob */ export function globAsync(pattern, ignore, allowEmptyPaths, cfg) { //Prepare glob config cfg = Object.assign({ignore}, cfg, {nodir: true}) //Run glob return glob(pattern, cfg).then(files => { //Error if no files match, unless allowed if (!allowEmptyPaths && files.length === 0) { throw new Error('No files match the pattern: ' + pattern) } //Return files return files }) } /** * Get paths (sync) */ export function pathsSync(patterns, config) { //Extract relevant config const {ignore, disableGlobs, glob: globConfig, cwd} = config //Not using globs? if (disableGlobs) { return patterns } //Prepare glob config const cfg = Object.assign({ignore}, globConfig, {nodir: true}) //Append CWD configuration if given (#56) if (cwd) { cfg.cwd = cwd } //Get paths const paths = patterns.map(pattern => glob.sync(pattern, cfg)) const flattened = [].concat.apply([], paths) //Prefix each path with CWD if given (#56) if (cwd) { return flattened.map(path => nodepath.join(cwd, path)) } //Return flattened return flattened } /** * Get paths asynchrously */ export async function pathsAsync(patterns, config) { //Extract relevant config const {ignore, disableGlobs, allowEmptyPaths, glob: cfg} = config //Not using globs? if (disableGlobs) { return patterns } //Prepare promises const promises = patterns .map(pattern => globAsync(pattern, ignore, allowEmptyPaths, cfg)) //Expand globs and flatten paths const paths = await Promise.all(promises) return [].concat.apply([], paths) } replace-in-file-main/src/helpers/paths.spec.js000066400000000000000000000026441511441262100215760ustar00rootroot00000000000000import {expect, use, should} from 'chai' import chaiAsPromised from 'chai-as-promised' import {pathsSync, pathsAsync} from './paths.js' //Enable should assertion style for usage with chai-as-promised should() use(chaiAsPromised) /** * Specs */ describe('helpers/path.js', () => { //Patterns const patterns = ['**/*.js', '**/*.json'] /** * pathsSync() */ describe('pathsSync()', () => { it('should prefix each path with cwd if specified', () => { const paths = pathsSync(patterns, { cwd: './src/helpers/', }) expect(paths).to.be.an('array') expect(paths).to.have.lengthOf(7) expect(paths[0]).to.equal('src/helpers/replace.js') }) it('should return patterns as is if globs have been disabled', () => { const paths = pathsSync(patterns, { disableGlobs: true, }) expect(paths).to.be.an('array') expect(paths).to.have.lengthOf(2) expect(paths[0]).to.equal('**/*.js') expect(paths[1]).to.equal('**/*.json') }) }) /** * pathsAsync() */ describe('pathsAsync()', () => { it('should return patterns as is if globs have been disabled', async () => { const paths = await pathsAsync(patterns, { disableGlobs: true, }) expect(paths).to.be.an('array') expect(paths).to.have.lengthOf(2) expect(paths[0]).to.equal('**/*.js') expect(paths[1]).to.equal('**/*.json') }) }) }) replace-in-file-main/src/helpers/process.js000066400000000000000000000042341511441262100212010ustar00rootroot00000000000000 /** * Run processors */ export function runProcessors(contents, processor, file) { //Ensure array and prepare result const processors = Array.isArray(processor) ? processor : [processor] //Run processors const newContents = processors .reduce((contents, processor) => processor(contents, file), contents) //Check if contents changed and prepare result const hasChanged = (newContents !== contents) const result = {file, hasChanged} //Return along with new contents return [result, newContents] } /** * Helper to process in a single file (sync) */ export function processSync(file, processor, config) { //Extract relevant config and read file contents const {encoding, dry, fsSync} = config const contents = fsSync.readFileSync(file, encoding) //Process contents const [result, newContents] = runProcessors(contents, processor, file) //Contents changed and not a dry run? Write to file if (result.hasChanged && !dry) { fsSync.writeFileSync(file, newContents, encoding) } //Return result return result } /** * Run processors (async) */ export async function runProcessorsAsync(contents, processorAsync, file) { //Ensure array and prepare result const processorAsyncs = Array.isArray(processorAsync) ? processorAsync : [processorAsync] //Run processors let newContents = contents for (const processor of processorAsyncs) { newContents = await processor(newContents, file) } //Check if contents changed and prepare result const hasChanged = (newContents !== contents) const result = {file, hasChanged} //Return along with new contents return [result, newContents] } /** * Helper to process in a single file (async) */ export async function processAsync(file, processor, config) { //Extract relevant config and read file contents const {encoding, dry, fs} = config const contents = await fs.readFile(file, encoding) //Make replacements const [result, newContents] = await runProcessorsAsync(contents, processor, file) //Contents changed and not a dry run? Write to file if (result.hasChanged && !dry) { await fs.writeFile(file, newContents, encoding) } //Return result return result } replace-in-file-main/src/helpers/replace.js000066400000000000000000000063161511441262100211410ustar00rootroot00000000000000 /** * Get replacement helper */ export function getReplacement(replace, isArray, i) { if (isArray && typeof replace[i] === 'undefined') { return null } if (isArray) { return replace[i] } return replace } /** * Escape string to make it safe for use in a regex */ export function escapeRegex(string) { if (typeof string === 'string') { return string.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&') } return string } /** * Helper to make replacements */ export function makeReplacements(contents, from, to, file, count) { //Turn into array if (!Array.isArray(from)) { from = [from] } //Check if replace value is an array and prepare result const isArray = Array.isArray(to) const result = {file} //Counting? Initialize number of matches if (count) { result.numMatches = 0 result.numReplacements = 0 } //Make replacements const newContents = from.reduce((contents, item, i) => { //Call function if given, passing in the filename if (typeof item === 'function') { item = item(file) } //Get replacement value let replacement = getReplacement(to, isArray, i) if (replacement === null) { return contents } //Call function if given, appending the filename if (typeof replacement === 'function') { const original = replacement replacement = (...args) => original(...args, file) } //Count matches if (count) { const matches = contents.match(escapeRegex(item)) if (matches) { const replacements = matches.filter(match => match !== replacement) result.numMatches += matches.length result.numReplacements += replacements.length } } //Make replacement return contents.replace(item, replacement) }, contents) //Check if changed result.hasChanged = (newContents !== contents) //Return result and new contents return [result, newContents] } /** * Helper to replace in a single file (sync) */ export function replaceSync(source, from, to, config) { //Extract relevant config and read file contents const {getTargetFile, encoding, dry, countMatches, fsSync} = config const contents = fsSync.readFileSync(source, encoding) //Replace contents and check if anything changed const [result, newContents] = makeReplacements( contents, from, to, source, countMatches ) //Get target file const target = getTargetFile(source) //Contents changed and not a dry run? Write to file if (result.hasChanged && !dry) { fsSync.writeFileSync(target, newContents, encoding) } //Return result return result } /** * Helper to replace in a single file (async) */ export async function replaceAsync(source, from, to, config) { //Extract relevant config and read file contents const {getTargetFile, encoding, dry, countMatches, fs} = config const contents = await fs.readFile(source, encoding) //Make replacements const [result, newContents] = makeReplacements( contents, from, to, source, countMatches ) //Get target file const target = getTargetFile(source) //Contents changed and not a dry run? Write to file if (result.hasChanged && !dry) { await fs.writeFile(target, newContents, encoding) } //Return result return result } replace-in-file-main/src/process-file.js000066400000000000000000000021341511441262100204510ustar00rootroot00000000000000import {parseConfig} from './helpers/config.js' import {logDryRun} from './helpers/handlers.js' import {pathsSync, pathsAsync} from './helpers/paths.js' import {processSync, processAsync} from './helpers/process.js' /** * Process a file (async) */ export async function processFile(config) { //Parse config config = parseConfig(config) const {files, processor, processorAsync, dry, verbose} = config //Dry run? logDryRun(dry && verbose) //Find paths and process them const paths = await pathsAsync(files, config) const promises = paths.map(path => processAsync(path, processor ?? processorAsync, config)) const results = await Promise.all(promises) //Return results return results } /** * Process a file (sync) */ export function processFileSync(config) { //Parse config config = parseConfig(config) const {files, processor, dry, verbose} = config //Dry run? logDryRun(dry && verbose) //Find paths and process them const paths = pathsSync(files, config) const results = paths.map(path => processSync(path, processor, config)) //Return results return results } replace-in-file-main/src/process-file.spec.js000066400000000000000000000373011511441262100214060ustar00rootroot00000000000000import {expect, use, should} from 'chai' import chaiAsPromised from 'chai-as-promised' import {processFile, processFileSync} from './process-file.js' import fsAsync from 'node:fs/promises' import fs from 'node:fs' //Enable should assertion style for usage with chai-as-promised should() use(chaiAsPromised) /** * Specifications */ describe('Process a file', () => { //Test JSON const testData = 'a re place c' /** * Prepare test files */ beforeEach(() => Promise.all([ fsAsync.writeFile('test1', testData, 'utf8'), fsAsync.writeFile('test2', testData, 'utf8'), fsAsync.writeFile('test3', 'nope', 'utf8'), ])) /** * Clean up test files */ afterEach(() => Promise.all([ fsAsync.unlink('test1'), fsAsync.unlink('test2'), fsAsync.unlink('test3'), ])) function fromToToProcessor(config) { const from = config.from const to = config.to delete config.from delete config.to config.processor = (content) => { return content.replace(from, to) } return config } function appendFileProcessor(config) { config.processor = (content, file) => { return `${content}${file}` } return config } /** * Async */ describe('Async', () => { it('should run processor', done => { processFile({ files: 'test1', processor: (input) => { return input.replace(/re\splace/g, 'b') }, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) done() }) }) it('should run processorAsync', done => { processFile({ files: 'test1', processorAsync: async (input) => { const replaceValue = await Promise.resolve('b') return input.replace(/re\splace/g, replaceValue) }, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) done() }) }) it('should replace contents in a single file with regex', done => { processFile(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) done() }) }) it('should replace contents with a string replacement', done => { processFile(fromToToProcessor({ files: 'test1', from: 're place', to: 'b', })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') done() }) }) it('should replace contents in a an array of files', done => { processFile(fromToToProcessor({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') done() }) }) it('should expand globs', done => { processFile(fromToToProcessor({ files: 'test*', from: /re\splace/g, to: 'b', })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') done() }) }) it('should expand globs while excluding ignored files', done => { processFile(fromToToProcessor({ files: 'test*', ignore: 'test1', from: /re\splace/g, to: 'b', })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') done() }) }) it('should replace substrings', done => { processFile(fromToToProcessor({ files: 'test1', from: /(re)\s(place)/g, to: '$2 $1', })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a place re c') done() }) }) it('should fulfill the promise on success', () => { return processFile(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })).should.be.fulfilled }) it('should reject the promise with an error on failure', () => { return expect(processFile(fromToToProcessor({ files: 'nope', from: /re\splace/g, to: 'b', }))).to.eventually.be.rejectedWith(Error) }) it('should not reject the promise if allowEmptyPaths is true', () => { return processFile(fromToToProcessor({ files: 'nope', allowEmptyPaths: true, from: /re\splace/g, to: 'b', })).should.be.fulfilled }) it('should return a results array', done => { processFile(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })).then(results => { expect(results).to.be.instanceof(Array) expect(results).to.have.length(1) expect(results[0].file).to.equal('test1') done() }) }) it('should mark if something was replaced', done => { processFile(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })).then(results => { expect(results[0].hasChanged).to.equal(true) done() }) }) it('should not mark if nothing was replaced', done => { processFile(fromToToProcessor({ files: 'test1', from: 'nope', to: 'b', })).then(results => { expect(results[0].hasChanged).to.equal(false) done() }) }) it('should return correct results for multiple files', done => { processFile(fromToToProcessor({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', })).then(results => { expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) done() }) }) it('should not replace in a dry run', done => { processFile(fromToToProcessor({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', dry: true, })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a re place c') done() }) }) it('should return changed files for a dry run', done => { processFile(fromToToProcessor({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', dry: true, })).then(results => { expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) done() }) }) it('should accept glob configuration', done => { processFile(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', allowEmptyPaths: true, glob: { ignore: ['test1'], }, })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a re place c') done() }) }) it('should ignore empty glob configuration', done => { processFile(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', glob: null, })).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') done() }) }) describe('fs', () => { it('reads and writes using a custom fs when provided', done => { const before = 'abc' let written const fs = { readFile: async () => { return before }, writeFile: async (_fileName, data) => { written = data }, } processFile({ files: 'test1', fs, processor: (input) => { return input.replace(/b/, 'z') }, }).then(() => { expect(written).to.equal('azc') done() }) }) }) }) /** * Sync */ describe('Sync', () => { it('should replace contents in a single file with regex', function() { processFileSync(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) }) it('should replace contents with a string replacement', function() { processFileSync(fromToToProcessor({ files: 'test1', from: 're place', to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') }) it('should replace contents in a an array of files', function() { processFileSync(fromToToProcessor({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should expand globs', function() { processFileSync(fromToToProcessor({ files: 'test*', from: /re\splace/g, to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should return a results array', function() { const results = processFileSync(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })) expect(results).to.be.instanceof(Array) expect(results).to.have.length(1) expect(results[0].file).to.equal('test1') }) it('should mark if something was replaced', function() { const results = processFileSync(fromToToProcessor({ files: 'test1', from: /re\splace/g, to: 'b', })) expect(results[0].hasChanged).to.equal(true) }) it('should not mark if nothing was replaced', function() { const results = processFileSync(fromToToProcessor({ files: 'test1', from: 'nope', to: 'b', })) expect(results[0].hasChanged).to.equal(false) }) it('should return correct results for multiple files', function() { const results = processFileSync(fromToToProcessor({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', })) expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) }) it('should expand globs while excluding ignored files', () => { processFileSync(fromToToProcessor({ files: 'test*', ignore: 'test1', from: /re\splace/g, to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') }) it('should support an array of ignored files', () => { processFileSync(fromToToProcessor({ files: 'test*', ignore: ['test1', 'test3'], from: /re\splace/g, to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') }) it('should not fail when the ignore parameter is undefined', () => { processFileSync(fromToToProcessor({ files: 'test*', ignore: undefined, from: /re\splace/g, to: 'b', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should work without expanding globs if disabled', () => { processFileSync(fromToToProcessor({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', disableGlobs: true, })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should not replace in a dry run', () => { processFileSync(fromToToProcessor({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', dry: true, })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a re place c') }) it('should return changed files for a dry run', () => { const results = processFileSync(fromToToProcessor({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', dry: true, })) expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) }) it('should pass filename to processor as second parameter', () => { processFileSync(appendFileProcessor({ files: 'test*', })) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') const test3 = fs.readFileSync('test3', 'utf8') expect(test1).to.equal(`${testData}test1`) expect(test2).to.equal(`${testData}test2`) expect(test3).to.equal('nopetest3') }) describe('fsSync', () => { it('reads and writes using a custom fsSync when provided', done => { const before = 'a' let written const fsSync = { readFileSync: () => { return before }, writeFileSync: (_fileName, data) => { written = data return data }, } const results = processFileSync({ files: 'test1', fsSync, processor: (input) => { return input.replace(/a/, 'z') }, }) expect(results[0].file).to.equal('test1') expect(written).to.equal('z') done() }) }) }) describe('module export', () => { it(`exports named processFile and processFileSync from module`, () => { expect(processFile).to.be.a('function') expect(processFileSync).to.be.a('function') }) }) }) replace-in-file-main/src/replace-in-file.js000066400000000000000000000030151511441262100210110ustar00rootroot00000000000000import {parseConfig} from './helpers/config.js' import {logDryRun} from './helpers/handlers.js' import {pathsSync, pathsAsync} from './helpers/paths.js' import {replaceSync, replaceAsync} from './helpers/replace.js' import {processFile, processFileSync} from './process-file.js' /** * Replace in file (async) */ export async function replaceInFile(config) { //If custom processor is provided use it instead if (config && (config.processor || config.processorAsync)) { return await processFile(config) } //Parse config config = parseConfig(config) const {files, from, to, dry, verbose} = config //Dry run? logDryRun(dry && verbose) //Find paths and process them const paths = await pathsAsync(files, config) const promises = paths.map(path => replaceAsync(path, from, to, config)) const results = await Promise.all(promises) //Return results return results } /** * Replace in file (sync) */ export function replaceInFileSync(config) { if (config && config.processorAsync) { throw new Error('ProcessorAsync cannot be used in synchronous mode') } //If custom processor is provided use it instead if (config && config.processor) { return processFileSync(config) } //Parse config config = parseConfig(config) const {files, from, to, dry, verbose} = config //Dry run? logDryRun(dry && verbose) //Find paths and process them const paths = pathsSync(files, config) const results = paths.map(path => replaceSync(path, from, to, config)) //Return results return results } replace-in-file-main/src/replace-in-file.spec.js000066400000000000000000000632511511441262100217520ustar00rootroot00000000000000import {expect, use, should} from 'chai' import chaiAsPromised from 'chai-as-promised' import {replaceInFile, replaceInFileSync} from './replace-in-file.js' import fsAsync from 'node:fs/promises' import fs from 'node:fs' //Enable should assertion style for usage with chai-as-promised should() use(chaiAsPromised) /** * Specs */ describe('Replace in file', () => { //Test JSON const testData = 'a re place c' const testData2 = `app.setVersion('\${sourceVersion}');` /** * Prepare test files */ beforeEach(() => Promise.all([ fsAsync.writeFile('test1', testData, 'utf8'), fsAsync.writeFile('test2', testData, 'utf8'), fsAsync.writeFile('test3', 'nope', 'utf8'), fsAsync.writeFile('test4', testData2, 'utf8'), ])) /** * Clean up test files */ afterEach(() => Promise.all([ fsAsync.unlink('test1'), fsAsync.unlink('test2'), fsAsync.unlink('test3'), fsAsync.unlink('test4'), ])) /** * Async */ describe('Async', () => { it('should replace contents in a single file with regex', done => { replaceInFile({ files: 'test1', from: /re\splace/g, to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) done() }) }) it('should pass file as an arg to a "from" function', done => { replaceInFile({ files: 'test1', from: (file) => { expect(file).to.equal('test1') return /re\splace/g }, to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) done() }) }) it(`should pass the match as first arg and file as last arg to a replacer function replace contents in a single file with regex`, done => { replaceInFile({ files: 'test1', from: /re\splace/g, to: (match, ...args) => { const file = args.pop() expect(match).to.equal('re place') expect(file).to.equal('test1') return 'b' }, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) done() }) }) it('should replace contents with a string replacement', done => { replaceInFile({ files: 'test1', from: 're place', to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') done() }) }) it(`should store in the correct target file if getTargetFile is used`, done => { replaceInFile({ files: 'test1', getTargetFile: () => 'test2', from: 're place', to: 'b', }) .then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') done() }) }) it(`should pass the match as first arg and file as last arg to a replacer function and replace contents with a string replacement`, done => { replaceInFile({ files: 'test1', from: 're place', to: (match, ...args) => { const file = args.pop() expect(match).to.equal('re place') expect(file).to.equal('test1') return 'b' }, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') done() }) }) it('should replace contents in a an array of files', done => { replaceInFile({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') done() }) }) it('should expand globs', done => { replaceInFile({ files: 'test*', from: /re\splace/g, to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') done() }) }) it('should expand globs while excluding ignored files', done => { replaceInFile({ files: 'test*', ignore: 'test1', from: /re\splace/g, to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') done() }) }) it('should replace substrings', done => { replaceInFile({ files: 'test1', from: /(re)\s(place)/g, to: '$2 $1', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a place re c') done() }) }) it('should fulfill the promise on success', () => { return replaceInFile({ files: 'test1', from: /re\splace/g, to: 'b', }).should.be.fulfilled }) it('should reject the promise with an error on failure', () => { return expect(replaceInFile({ files: 'nope', from: /re\splace/g, to: 'b', })).to.eventually.be.rejectedWith(Error) }) it('should not reject the promise if allowEmptyPaths is true', () => { return replaceInFile({ files: 'nope', allowEmptyPaths: true, from: /re\splace/g, to: 'b', }).should.be.fulfilled }) it('should return a results array', done => { replaceInFile({ files: 'test1', from: /re\splace/g, to: 'b', }).then(results => { expect(results).to.be.instanceof(Array) expect(results).to.have.length(1) expect(results[0].file).to.equal('test1') done() }) }) it('should mark if something was replaced', done => { replaceInFile({ files: 'test1', from: /re\splace/g, to: 'b', }).then(results => { expect(results[0].hasChanged).to.equal(true) done() }) }) it('should not mark if nothing was replaced', done => { replaceInFile({ files: 'test1', from: 'nope', to: 'b', }).then(results => { expect(results[0].hasChanged).to.equal(false) done() }) }) it('should return correct results for multiple files', done => { replaceInFile({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', }).then(results => { expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) done() }) }) it('should make multiple replacements with the same string', done => { replaceInFile({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: 'b', }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b b c') expect(test2).to.equal('a b b c') done() }) }) it('should make multiple replacements with different strings', done => { replaceInFile({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b', 'e'], }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b e c') expect(test2).to.equal('a b e c') done() }) }) it('should not replace with missing replacement values', done => { replaceInFile({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b'], }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b place c') expect(test2).to.equal('a b place c') done() }) }) it('should not replace in a dry run', done => { replaceInFile({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', dry: true, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a re place c') done() }) }) it('should return changed files for a dry run', done => { replaceInFile({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', dry: true, }).then(results => { expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) done() }) }) it('should accept glob configuration', done => { replaceInFile({ files: 'test1', from: /re\splace/g, to: 'b', allowEmptyPaths: true, glob: { ignore: ['test1'], }, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a re place c') done() }) }) it('should ignore empty glob configuration', done => { replaceInFile({ files: 'test1', from: /re\splace/g, to: 'b', glob: null, }).then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') done() }) }) it('should count matches if specified in config', done => { replaceInFile({ files: 'test1', from: [/re/g, /place/g], to: 'test', countMatches: true, }).then(results => { expect(results[0].numMatches).to.equal(2) done() }) }) it('should not count matches if not specified in config', done => { replaceInFile({ files: 'test1', from: [/re/g, /place/g], to: 'test', }).then(results => { expect(results[0].numMatches).to.be.undefined done() }) }) it('should return 0 matches if match not found', done => { replaceInFile({ files: 'test1', from: 'nope', to: 'test', countMatches: true, }).then(results => { expect(results[0].numMatches).to.equal(0) done() }) }) //Processors describe('processors', () => { it('uses custom processor', done => { replaceInFile({ files: 'test1', processor: input => input.replace(/place/, 'plop'), }) .then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a re plop c') done() }) }) it('uses array of custom processors', done => { replaceInFile({ files: 'test1', processor: [ input => input.replace(/place/, 'plop'), input => input.replace(/plop/, 'bloop'), ], }) .then(() => { const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a re bloop c') done() }) }) }) describe('fs', () => { it('reads and writes using a custom fs when provided', done => { const before = 'a' let written const fs = { readFile: async () => { return before }, writeFile: async (_fileName, data) => { written = data }, } replaceInFile({ files: 'test1', from: /a/, fs, to: 'z', }).then(() => { expect(written).to.equal('z') done() }) }) }) }) /** * Sync */ describe('Sync', () => { it('should error with processorAsync', function() { return expect(() => replaceInFileSync({ files: 'test1', processorAsync: async (input) => { const replaceValue = await Promise.resolve('b') return input.replace(/re\splace/g, replaceValue) }, })).to.throw(Error) }) it('should replace contents in a single file with regex', function() { replaceInFileSync({ files: 'test1', from: /re\splace/g, to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) }) it('should pass file as an arg to a "from" function', function() { replaceInFileSync({ files: 'test1', from: (file) => { expect(file).to.equal('test1') return /re\splace/g }, to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) }) it(`should pass the match as first arg and file as last arg to a replacer function replace contents in a single file with regex`, function() { replaceInFileSync({ files: 'test1', from: /re\splace/g, to: (match, ...args) => { const file = args.pop() expect(match).to.equal('re place') expect(file).to.equal('test1') return 'b' }, }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal(testData) }) it('should replace contents with a string replacement', function() { replaceInFileSync({ files: 'test1', from: 're place', to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') }) it(`should store in the correct target file if getTargetFile is used`, () => { replaceInFileSync({ files: 'test1', getTargetFile: () => 'test2', from: 're place', to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') }) it(`should pass the match as first arg and file as last arg to a replacer function and replace contents with a string replacement`, function() { replaceInFileSync({ files: 'test1', from: 're place', to: (match, ...args) => { const file = args.pop() expect(match).to.equal('re place') expect(file).to.equal('test1') return 'b' }, }) const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a b c') }) it('should replace contents in a an array of files', function() { replaceInFileSync({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should expand globs', function() { replaceInFileSync({ files: 'test*', from: /re\splace/g, to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should return a results array', function() { const results = replaceInFileSync({ files: 'test1', from: /re\splace/g, to: 'b', }) expect(results).to.be.instanceof(Array) expect(results).to.have.length(1) expect(results[0].file).to.equal('test1') }) it('should mark if something was replaced', function() { const results = replaceInFileSync({ files: 'test1', from: /re\splace/g, to: 'b', }) expect(results[0].hasChanged).to.equal(true) }) it('should not mark if nothing was replaced', function() { const results = replaceInFileSync({ files: 'test1', from: 'nope', to: 'b', }) expect(results[0].hasChanged).to.equal(false) }) it('should return correct results for multiple files', function() { const results = replaceInFileSync({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', }) expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) }) it('should make multiple replacements with the same string', () => { replaceInFileSync({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b b c') expect(test2).to.equal('a b b c') }) it('should make multiple replacements with different strings', () => { replaceInFileSync({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b', 'e'], }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b e c') expect(test2).to.equal('a b e c') }) it('should not replace with missing replacement values', () => { replaceInFileSync({ files: ['test1', 'test2', 'test3'], from: [/re/g, /place/g], to: ['b'], }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b place c') expect(test2).to.equal('a b place c') }) it('should expand globs while excluding ignored files', () => { replaceInFileSync({ files: 'test*', ignore: 'test1', from: /re\splace/g, to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') }) it('should support an array of ignored files', () => { replaceInFileSync({ files: 'test*', ignore: ['test1', 'test3'], from: /re\splace/g, to: 'b', }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a b c') }) it('should work without expanding globs if disabled', () => { replaceInFileSync({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', disableGlobs: true, }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a b c') expect(test2).to.equal('a b c') }) it('should not replace in a dry run', () => { replaceInFileSync({ files: ['test1', 'test2'], from: /re\splace/g, to: 'b', dry: true, }) const test1 = fs.readFileSync('test1', 'utf8') const test2 = fs.readFileSync('test2', 'utf8') expect(test1).to.equal('a re place c') expect(test2).to.equal('a re place c') }) it('should return changed files for a dry run', () => { const results = replaceInFileSync({ files: ['test1', 'test2', 'test3'], from: /re\splace/g, to: 'b', dry: true, }) expect(results).to.have.length(3) expect(results[0].file).to.equal('test1') expect(results[0].hasChanged).to.equal(true) expect(results[1].file).to.equal('test2') expect(results[1].hasChanged).to.equal(true) expect(results[2].file).to.equal('test3') expect(results[2].hasChanged).to.equal(false) }) it('should count matches and replacements if specified in config', () => { const results = replaceInFileSync({ files: 'test1', from: [/re/g, /place/g], to: 'test', countMatches: true, }) expect(results[0].numMatches).to.equal(2) expect(results[0].numReplacements).to.equal(2) }) it('should differentiate between matches and replacements', () => { const results = replaceInFileSync({ files: 'test1', from: [/re/g, /place/g], to: 're', countMatches: true, }) expect(results[0].numMatches).to.equal(2) expect(results[0].numReplacements).to.equal(1) }) it('should count multiple replacements correctly', () => { const results = replaceInFileSync({ files: 'test1', from: [/re/g, /place/g], to: 'place', countMatches: true, }) expect(results[0].numMatches).to.equal(3) expect(results[0].numReplacements).to.equal(1) }) it(`should not count matches or replacements if not specified in config`, () => { const results = replaceInFileSync({ files: 'test1', from: [/re/g, /place/g], to: 'test', }) expect(results[0].numMatches).to.be.undefined expect(results[0].numReplacements).to.be.undefined }) it('should return 0 matches and replacements if match not found', () => { const results = replaceInFileSync({ files: 'test1', from: 'nope', to: 'test', countMatches: true, }) expect(results[0].numMatches).to.equal(0) expect(results[0].numReplacements).to.equal(0) }) describe('fsSync', () => { it('reads and writes using a custom fsSync when provided', () => { const before = 'a' let written const fsSync = { readFileSync: () => { return before }, writeFileSync: (_fileName, data) => { written = data return data }, } const results = replaceInFileSync({ files: 'test1', from: /a/, fsSync, to: 'z', }) expect(results[0].file).to.equal('test1') expect(written).to.equal('z') }) }) //Processors describe('processors', () => { it('uses custom processor', () => { replaceInFileSync({ files: 'test1', processor: input => input.replace(/place/, 'plop'), }) const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a re plop c') }) it('uses array of custom processors', () => { replaceInFileSync({ files: 'test1', processor: [ input => input.replace(/place/, 'plop'), input => input.replace(/plop/, 'bloop'), ], }) const test1 = fs.readFileSync('test1', 'utf8') expect(test1).to.equal('a re bloop c') }) }) //#197 describe('#197', () => { before(() => fs.writeFileSync('test197', 'ABC 123\n6666666\nDEF 456', 'utf8')) after(() => fs.unlinkSync('test197')) it('should replace contents when a regex string is passed', () => { replaceInFileSync({ files: 'test197', from: '/\\w{3} \\d{3}/g', to: 'replaced', }) const test197 = fs.readFileSync('test197', 'utf8') expect(test197).to.equal('replaced\n6666666\nreplaced') }) }) }) describe('module export', () => { it(`exports named replaceInFile and replaceInFileSync from module`, () => { expect(replaceInFile).to.be.a('function') expect(replaceInFileSync).to.be.a('function') }) }) //https://github.com/adamreisnz/replace-in-file/issues/156 describe('special characters', () => { it(`should replace contents with special characters and count matches correctly`, done => { const results = replaceInFileSync({ files: 'test4', from: '${sourceVersion}', to: '1.0.0', countMatches: true, }) const test4 = fs.readFileSync('test4', 'utf8') expect(test4).to.equal(`app.setVersion('1.0.0');`) expect(results).to.have.length(1) expect(results[0].file).to.equal('test4') expect(results[0].hasChanged).to.equal(true) expect(results[0].numMatches).to.equal(1) done() }) it(`should replace contents with special characters and count matches correctly (2)`, done => { const results = replaceInFileSync({ files: 'test4', from: `\${sourceVersion}')`, to: '1.0.0', countMatches: true, }) const test4 = fs.readFileSync('test4', 'utf8') expect(test4).to.equal(`app.setVersion('1.0.0;`) expect(results).to.have.length(1) expect(results[0].file).to.equal('test4') expect(results[0].hasChanged).to.equal(true) expect(results[0].numMatches).to.equal(1) done() }) }) }) replace-in-file-main/types/000077500000000000000000000000001511441262100160755ustar00rootroot00000000000000replace-in-file-main/types/index.d.ts000066400000000000000000000033061511441262100200000ustar00rootroot00000000000000 declare module 'replace-in-file' { export function replaceInFile(config: ReplaceInFileConfig & { from?: never, to?: never, processor: ReplaceInFileConfig["processor"] }): Promise; export function replaceInFile(config: ReplaceInFileConfig & { from: ReplaceInFileConfig["from"], to: ReplaceInFileConfig["to"], processor?: never }): Promise; export default replaceInFile; export namespace replaceInFile { export function replaceInFileSync(config: ReplaceInFileConfig): ReplaceResult[]; export function replaceInFile(config: ReplaceInFileConfig): Promise; } export function replaceInFileSync(config: ReplaceInFileConfig): ReplaceResult[]; export type From = string | RegExp | FromCallback; export type To = string | ToCallback; export interface ReplaceInFileConfig { files: string | string[]; ignore?: string | string[]; from?: From | Array; to?: To | Array; getTargetFile?(source: string): string; countMatches?: boolean; allowEmptyPaths?: boolean; disableGlobs?: boolean; encoding?: string; dry?: boolean; glob?: object; processor?: ProcessorCallback | Array; processorAsync?: ProcessorAsyncCallback | Array; } export interface ReplaceResult { file: string; hasChanged: boolean; numMatches?: number, numReplacements?: number, } } type FromCallback = (file: string) => string | RegExp | (RegExp | string)[]; type ToCallback = (match: string, file: string) => string | string[]; type ProcessorCallback = (input: string, file: string) => string; type ProcessorAsyncCallback = (input: string, file: string) => Promise; replace-in-file-main/yarn.lock000066400000000000000000001717571511441262100165760ustar00rootroot00000000000000# This file is generated by running "yarn install" inside your project. # Manual changes might be lost - proceed with caution! __metadata: version: 8 cacheKey: 10c0 "@bcoe/v8-coverage@npm:^1.0.1": version: 1.0.2 resolution: "@bcoe/v8-coverage@npm:1.0.2" checksum: 10c0/1eb1dc93cc17fb7abdcef21a6e7b867d6aa99a7ec88ec8207402b23d9083ab22a8011213f04b2cf26d535f1d22dc26139b7929e6c2134c254bd1e14ba5e678c3 languageName: node linkType: hard "@eslint-community/eslint-utils@npm:^4.8.0": version: 4.9.0 resolution: "@eslint-community/eslint-utils@npm:4.9.0" dependencies: eslint-visitor-keys: "npm:^3.4.3" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817 languageName: node linkType: hard "@eslint-community/regexpp@npm:^4.12.1": version: 4.12.2 resolution: "@eslint-community/regexpp@npm:4.12.2" checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d languageName: node linkType: hard "@eslint/config-array@npm:^0.21.1": version: 0.21.1 resolution: "@eslint/config-array@npm:0.21.1" dependencies: "@eslint/object-schema": "npm:^2.1.7" debug: "npm:^4.3.1" minimatch: "npm:^3.1.2" checksum: 10c0/2f657d4edd6ddcb920579b72e7a5b127865d4c3fb4dda24f11d5c4f445a93ca481aebdbd6bf3291c536f5d034458dbcbb298ee3b698bc6c9dd02900fe87eec3c languageName: node linkType: hard "@eslint/config-helpers@npm:^0.4.2": version: 0.4.2 resolution: "@eslint/config-helpers@npm:0.4.2" dependencies: "@eslint/core": "npm:^0.17.0" checksum: 10c0/92efd7a527b2d17eb1a148409d71d80f9ac160b565ac73ee092252e8bf08ecd08670699f46b306b94f13d22e88ac88a612120e7847570dd7cdc72f234d50dcb4 languageName: node linkType: hard "@eslint/core@npm:^0.17.0": version: 0.17.0 resolution: "@eslint/core@npm:0.17.0" dependencies: "@types/json-schema": "npm:^7.0.15" checksum: 10c0/9a580f2246633bc752298e7440dd942ec421860d1946d0801f0423830e67887e4aeba10ab9a23d281727a978eb93d053d1922a587d502942a713607f40ed704e languageName: node linkType: hard "@eslint/eslintrc@npm:^3.3.1": version: 3.3.3 resolution: "@eslint/eslintrc@npm:3.3.3" dependencies: ajv: "npm:^6.12.4" debug: "npm:^4.3.2" espree: "npm:^10.0.1" globals: "npm:^14.0.0" ignore: "npm:^5.2.0" import-fresh: "npm:^3.2.1" js-yaml: "npm:^4.1.1" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" checksum: 10c0/532c7acc7ddd042724c28b1f020bd7bf148fcd4653bb44c8314168b5f772508c842ce4ee070299cac51c5c5757d2124bdcfcef5551c8c58ff9986e3e17f2260d languageName: node linkType: hard "@eslint/js@npm:9.39.1, @eslint/js@npm:^9.39.1": version: 9.39.1 resolution: "@eslint/js@npm:9.39.1" checksum: 10c0/6f7f26f8cdb7ad6327bbf9741973b6278eb946f18f70e35406e88194b0d5c522d0547a34a02f2a208eec95c5d1388cdf7ccb20039efd2e4cb6655615247a50f1 languageName: node linkType: hard "@eslint/object-schema@npm:^2.1.7": version: 2.1.7 resolution: "@eslint/object-schema@npm:2.1.7" checksum: 10c0/936b6e499853d1335803f556d526c86f5fe2259ed241bc665000e1d6353828edd913feed43120d150adb75570cae162cf000b5b0dfc9596726761c36b82f4e87 languageName: node linkType: hard "@eslint/plugin-kit@npm:^0.4.1": version: 0.4.1 resolution: "@eslint/plugin-kit@npm:0.4.1" dependencies: "@eslint/core": "npm:^0.17.0" levn: "npm:^0.4.1" checksum: 10c0/51600f78b798f172a9915dffb295e2ffb44840d583427bc732baf12ecb963eb841b253300e657da91d890f4b323d10a1bd12934bf293e3018d8bb66fdce5217b languageName: node linkType: hard "@humanfs/core@npm:^0.19.1": version: 0.19.1 resolution: "@humanfs/core@npm:0.19.1" checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 languageName: node linkType: hard "@humanfs/node@npm:^0.16.6": version: 0.16.7 resolution: "@humanfs/node@npm:0.16.7" dependencies: "@humanfs/core": "npm:^0.19.1" "@humanwhocodes/retry": "npm:^0.4.0" checksum: 10c0/9f83d3cf2cfa37383e01e3cdaead11cd426208e04c44adcdd291aa983aaf72d7d3598844d2fe9ce54896bb1bf8bd4b56883376611c8905a19c44684642823f30 languageName: node linkType: hard "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 languageName: node linkType: hard "@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": version: 0.4.3 resolution: "@humanwhocodes/retry@npm:0.4.3" checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 languageName: node linkType: hard "@isaacs/balanced-match@npm:^4.0.1": version: 4.0.1 resolution: "@isaacs/balanced-match@npm:4.0.1" checksum: 10c0/7da011805b259ec5c955f01cee903da72ad97c5e6f01ca96197267d3f33103d5b2f8a1af192140f3aa64526c593c8d098ae366c2b11f7f17645d12387c2fd420 languageName: node linkType: hard "@isaacs/brace-expansion@npm:^5.0.0": version: 5.0.0 resolution: "@isaacs/brace-expansion@npm:5.0.0" dependencies: "@isaacs/balanced-match": "npm:^4.0.1" checksum: 10c0/b4d4812f4be53afc2c5b6c545001ff7a4659af68d4484804e9d514e183d20269bb81def8682c01a22b17c4d6aed14292c8494f7d2ac664e547101c1a905aa977 languageName: node linkType: hard "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" dependencies: string-width: "npm:^5.1.2" string-width-cjs: "npm:string-width@^4.2.0" strip-ansi: "npm:^7.0.1" strip-ansi-cjs: "npm:strip-ansi@^6.0.1" wrap-ansi: "npm:^8.1.0" wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e languageName: node linkType: hard "@istanbuljs/schema@npm:^0.1.2": version: 0.1.2 resolution: "@istanbuljs/schema@npm:0.1.2" checksum: 10c0/0bd98d140df9afe03c1edc54f5172ec07c114cb1a8771e7be6d3d28dc76c5292eb31fb6cf1834c1eb786c35920687487b46f67736a6c79034bea3f2ca1a93aec languageName: node linkType: hard "@istanbuljs/schema@npm:^0.1.3": version: 0.1.3 resolution: "@istanbuljs/schema@npm:0.1.3" checksum: 10c0/61c5286771676c9ca3eb2bd8a7310a9c063fb6e0e9712225c8471c582d157392c88f5353581c8c9adbe0dff98892317d2fdfc56c3499aa42e0194405206a963a languageName: node linkType: hard "@jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e languageName: node linkType: hard "@jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: 10c0/0c6b5ae663087558039052a626d2d7ed5208da36cfd707dcc5cea4a07cfc918248403dcb5989a8f7afaf245ce0573b7cc6fd94c4a30453bd10e44d9363940ba5 languageName: node linkType: hard "@jridgewell/trace-mapping@npm:^0.3.12": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: "@jridgewell/resolve-uri": "npm:^3.1.0" "@jridgewell/sourcemap-codec": "npm:^1.4.14" checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 languageName: node linkType: hard "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd languageName: node linkType: hard "@types/color-name@npm:^1.1.1": version: 1.1.1 resolution: "@types/color-name@npm:1.1.1" checksum: 10c0/2abeac8d8d833e0622c66f21487cc8b522792abb2eff2e40df0e3e53261728cb65bab590edf24953eb8d8653ec88044dc801d9a4e58c489a0f10c025de522868 languageName: node linkType: hard "@types/estree@npm:^1.0.6": version: 1.0.8 resolution: "@types/estree@npm:1.0.8" checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 languageName: node linkType: hard "@types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.6 resolution: "@types/istanbul-lib-coverage@npm:2.0.6" checksum: 10c0/3948088654f3eeb45363f1db158354fb013b362dba2a5c2c18c559484d5eb9f6fd85b23d66c0a7c2fcfab7308d0a585b14dadaca6cc8bf89ebfdc7f8f5102fb7 languageName: node linkType: hard "@types/json-schema@npm:^7.0.15": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db languageName: node linkType: hard "acorn-jsx@npm:^5.3.2": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 languageName: node linkType: hard "acorn@npm:^8.12.0": version: 8.12.0 resolution: "acorn@npm:8.12.0" bin: acorn: bin/acorn checksum: 10c0/a19f9dead009d3b430fa3c253710b47778cdaace15b316de6de93a68c355507bc1072a9956372b6c990cbeeb167d4a929249d0faeb8ae4bb6911d68d53299549 languageName: node linkType: hard "acorn@npm:^8.15.0": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: acorn: bin/acorn checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec languageName: node linkType: hard "ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: fast-deep-equal: "npm:^3.1.1" fast-json-stable-stringify: "npm:^2.0.0" json-schema-traverse: "npm:^0.4.1" uri-js: "npm:^4.2.2" checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 languageName: node linkType: hard "ansi-regex@npm:^5.0.0, ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 languageName: node linkType: hard "ansi-regex@npm:^6.0.1": version: 6.0.1 resolution: "ansi-regex@npm:6.0.1" checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 languageName: node linkType: hard "ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": version: 4.2.0 resolution: "ansi-styles@npm:4.2.0" dependencies: "@types/color-name": "npm:^1.1.1" color-convert: "npm:^2.0.1" checksum: 10c0/866d994769663a7897f7c3bf77abebb324ec40880cd56e621df7b61978323dd93183523ee254ce6730ed93bea064119255be79aaf5082d0d8268aa3091874122 languageName: node linkType: hard "ansi-styles@npm:^6.1.0": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c languageName: node linkType: hard "ansi-styles@npm:^6.2.1": version: 6.2.3 resolution: "ansi-styles@npm:6.2.3" checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868 languageName: node linkType: hard "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e languageName: node linkType: hard "balanced-match@npm:^1.0.0": version: 1.0.0 resolution: "balanced-match@npm:1.0.0" checksum: 10c0/d45f1aeec59d87562cd65415e2890b9fd6ab7fa89941a46fb2eb505e2165158680ee1be7110586cf86f3a9599f1b88ec4a7fcf57594560ca37814a560ab95f41 languageName: node linkType: hard "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" dependencies: balanced-match: "npm:^1.0.0" concat-map: "npm:0.0.1" checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668 languageName: node linkType: hard "brace-expansion@npm:^2.0.1": version: 2.0.1 resolution: "brace-expansion@npm:2.0.1" dependencies: balanced-match: "npm:^1.0.0" checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f languageName: node linkType: hard "browser-stdout@npm:^1.3.1": version: 1.3.1 resolution: "browser-stdout@npm:1.3.1" checksum: 10c0/c40e482fd82be872b6ea7b9f7591beafbf6f5ba522fe3dade98ba1573a1c29a11101564993e4eb44e5488be8f44510af072df9a9637c739217eb155ceb639205 languageName: node linkType: hard "c8@npm:^10.1.3": version: 10.1.3 resolution: "c8@npm:10.1.3" dependencies: "@bcoe/v8-coverage": "npm:^1.0.1" "@istanbuljs/schema": "npm:^0.1.3" find-up: "npm:^5.0.0" foreground-child: "npm:^3.1.1" istanbul-lib-coverage: "npm:^3.2.0" istanbul-lib-report: "npm:^3.0.1" istanbul-reports: "npm:^3.1.6" test-exclude: "npm:^7.0.1" v8-to-istanbul: "npm:^9.0.0" yargs: "npm:^17.7.2" yargs-parser: "npm:^21.1.1" peerDependencies: monocart-coverage-reports: ^2 peerDependenciesMeta: monocart-coverage-reports: optional: true bin: c8: bin/c8.js checksum: 10c0/1265ddbcb0e624fe200978e9263faf948cb9694ce8e6b858adbb14f1186de2e6c451aa4aabb821e9eb7f1972859e14691eaf2ff12ad96be7a3fc0e39946fc569 languageName: node linkType: hard "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 languageName: node linkType: hard "camelcase@npm:^6.0.0": version: 6.2.0 resolution: "camelcase@npm:6.2.0" checksum: 10c0/d9f403a6153394c5bc68ec9c2672df1d04f00a7847708be12641b483b936cbfaaf14d891f92bb0026184e03923be24acd15a0476761e1286eec484d68f615fe5 languageName: node linkType: hard "chai-as-promised@npm:^8.0.2": version: 8.0.2 resolution: "chai-as-promised@npm:8.0.2" dependencies: check-error: "npm:^2.1.1" peerDependencies: chai: ">= 2.1.2 < 7" checksum: 10c0/829bcd98c04f0b108b2f7379efd33c668e53fbf0bda8d460dc63c96a709fd5de79909392aa78b4256de16a4d57640641d7affc516111e371d6e9f6aec1cc6c8a languageName: node linkType: hard "chai@npm:^6.2.1": version: 6.2.1 resolution: "chai@npm:6.2.1" checksum: 10c0/0c2d84392d7c6d44ca5d14d94204f1760e22af68b83d1f4278b5c4d301dabfc0242da70954dd86b1eda01e438f42950de6cf9d569df2103678538e4014abe50b languageName: node linkType: hard "chalk@npm:^4.0.0": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: ansi-styles: "npm:^4.1.0" supports-color: "npm:^7.1.0" checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 languageName: node linkType: hard "chalk@npm:^4.1.0": version: 4.1.0 resolution: "chalk@npm:4.1.0" dependencies: ansi-styles: "npm:^4.1.0" supports-color: "npm:^7.1.0" checksum: 10c0/3787bd65ecd98ab3a1acc3b4f71d006268a675875e49ee6ea75fb54ba73d268b97544368358c18c42445e408e076ae8ad5cec8fbad36942a2c7ac654883dc61e languageName: node linkType: hard "chalk@npm:^5.6.2": version: 5.6.2 resolution: "chalk@npm:5.6.2" checksum: 10c0/99a4b0f0e7991796b1e7e3f52dceb9137cae2a9dfc8fc0784a550dc4c558e15ab32ed70b14b21b52beb2679b4892b41a0aa44249bcb996f01e125d58477c6976 languageName: node linkType: hard "check-error@npm:^2.1.1": version: 2.1.1 resolution: "check-error@npm:2.1.1" checksum: 10c0/979f13eccab306cf1785fa10941a590b4e7ea9916ea2a4f8c87f0316fc3eab07eabefb6e587424ef0f88cbcd3805791f172ea739863ca3d7ce2afc54641c7f0e languageName: node linkType: hard "chokidar@npm:^4.0.1": version: 4.0.3 resolution: "chokidar@npm:4.0.3" dependencies: readdirp: "npm:^4.0.1" checksum: 10c0/a58b9df05bb452f7d105d9e7229ac82fa873741c0c40ddcc7bb82f8a909fbe3f7814c9ebe9bc9a2bef9b737c0ec6e2d699d179048ef06ad3ec46315df0ebe6ad languageName: node linkType: hard "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" dependencies: string-width: "npm:^4.2.0" strip-ansi: "npm:^6.0.1" wrap-ansi: "npm:^7.0.0" checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 languageName: node linkType: hard "cliui@npm:^9.0.1": version: 9.0.1 resolution: "cliui@npm:9.0.1" dependencies: string-width: "npm:^7.2.0" strip-ansi: "npm:^7.1.0" wrap-ansi: "npm:^9.0.0" checksum: 10c0/13441832e9efe7c7a76bd2b8e683555c478d461a9f249dc5db9b17fe8d4b47fa9277b503914b90bd00e4a151abb6b9b02b2288972ffe2e5e3ca40bcb1c2330d3 languageName: node linkType: hard "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" dependencies: color-name: "npm:~1.1.4" checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 languageName: node linkType: hard "color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 languageName: node linkType: hard "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f languageName: node linkType: hard "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b languageName: node linkType: hard "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: path-key: "npm:^3.1.0" shebang-command: "npm:^2.0.0" which: "npm:^2.0.1" checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 languageName: node linkType: hard "debug@npm:^4.3.1": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true checksum: 10c0/cedbec45298dd5c501d01b92b119cd3faebe5438c3917ff11ae1bff86a6c722930ac9c8659792824013168ba6db7c4668225d845c633fbdafbbf902a6389f736 languageName: node linkType: hard "debug@npm:^4.3.2": version: 4.3.5 resolution: "debug@npm:4.3.5" dependencies: ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true checksum: 10c0/082c375a2bdc4f4469c99f325ff458adad62a3fc2c482d59923c260cb08152f34e2659f72b3767db8bb2f21ca81a60a42d1019605a412132d7b9f59363a005cc languageName: node linkType: hard "debug@npm:^4.3.5": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: ms: "npm:^2.1.3" peerDependenciesMeta: supports-color: optional: true checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 languageName: node linkType: hard "decamelize@npm:^4.0.0": version: 4.0.0 resolution: "decamelize@npm:4.0.0" checksum: 10c0/e06da03fc05333e8cd2778c1487da67ffbea5b84e03ca80449519b8fa61f888714bbc6f459ea963d5641b4aa98832130eb5cd193d90ae9f0a27eee14be8e278d languageName: node linkType: hard "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c languageName: node linkType: hard "diff@npm:^7.0.0": version: 7.0.0 resolution: "diff@npm:7.0.0" checksum: 10c0/251fd15f85ffdf814cfc35a728d526b8d2ad3de338dcbd011ac6e57c461417090766b28995f8ff733135b5fbc3699c392db1d5e27711ac4e00244768cd1d577b languageName: node linkType: hard "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 languageName: node linkType: hard "emoji-regex@npm:^10.3.0": version: 10.6.0 resolution: "emoji-regex@npm:10.6.0" checksum: 10c0/1e4aa097bb007301c3b4b1913879ae27327fdc48e93eeefefe3b87e495eb33c5af155300be951b4349ff6ac084f4403dc9eff970acba7c1c572d89396a9a32d7 languageName: node linkType: hard "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 languageName: node linkType: hard "emoji-regex@npm:^9.2.2": version: 9.2.2 resolution: "emoji-regex@npm:9.2.2" checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 languageName: node linkType: hard "escalade@npm:^3.1.1": version: 3.1.1 resolution: "escalade@npm:3.1.1" checksum: 10c0/afd02e6ca91ffa813e1108b5e7756566173d6bc0d1eb951cb44d6b21702ec17c1cf116cfe75d4a2b02e05acb0b808a7a9387d0d1ca5cf9c04ad03a8445c3e46d languageName: node linkType: hard "escape-string-regexp@npm:^4.0.0": version: 4.0.0 resolution: "escape-string-regexp@npm:4.0.0" checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 languageName: node linkType: hard "eslint-scope@npm:^8.4.0": version: 8.4.0 resolution: "eslint-scope@npm:8.4.0" dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^5.2.0" checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 languageName: node linkType: hard "eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 languageName: node linkType: hard "eslint-visitor-keys@npm:^4.0.0": version: 4.0.0 resolution: "eslint-visitor-keys@npm:4.0.0" checksum: 10c0/76619f42cf162705a1515a6868e6fc7567e185c7063a05621a8ac4c3b850d022661262c21d9f1fc1d144ecf0d5d64d70a3f43c15c3fc969a61ace0fb25698cf5 languageName: node linkType: hard "eslint-visitor-keys@npm:^4.2.1": version: 4.2.1 resolution: "eslint-visitor-keys@npm:4.2.1" checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 languageName: node linkType: hard "eslint@npm:^9.39.1": version: 9.39.1 resolution: "eslint@npm:9.39.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.8.0" "@eslint-community/regexpp": "npm:^4.12.1" "@eslint/config-array": "npm:^0.21.1" "@eslint/config-helpers": "npm:^0.4.2" "@eslint/core": "npm:^0.17.0" "@eslint/eslintrc": "npm:^3.3.1" "@eslint/js": "npm:9.39.1" "@eslint/plugin-kit": "npm:^0.4.1" "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" "@humanwhocodes/retry": "npm:^0.4.2" "@types/estree": "npm:^1.0.6" ajv: "npm:^6.12.4" chalk: "npm:^4.0.0" cross-spawn: "npm:^7.0.6" debug: "npm:^4.3.2" escape-string-regexp: "npm:^4.0.0" eslint-scope: "npm:^8.4.0" eslint-visitor-keys: "npm:^4.2.1" espree: "npm:^10.4.0" esquery: "npm:^1.5.0" esutils: "npm:^2.0.2" fast-deep-equal: "npm:^3.1.3" file-entry-cache: "npm:^8.0.0" find-up: "npm:^5.0.0" glob-parent: "npm:^6.0.2" ignore: "npm:^5.2.0" imurmurhash: "npm:^0.1.4" is-glob: "npm:^4.0.0" json-stable-stringify-without-jsonify: "npm:^1.0.1" lodash.merge: "npm:^4.6.2" minimatch: "npm:^3.1.2" natural-compare: "npm:^1.4.0" optionator: "npm:^0.9.3" peerDependencies: jiti: "*" peerDependenciesMeta: jiti: optional: true bin: eslint: bin/eslint.js checksum: 10c0/59b2480639404ba24578ca480f973683b87b7aac8aa7e349240474a39067804fd13cd8b9cb22fee074170b8c7c563b57bab703ec0f0d3f81ea017e5d2cad299d languageName: node linkType: hard "espree@npm:^10.0.1": version: 10.1.0 resolution: "espree@npm:10.1.0" dependencies: acorn: "npm:^8.12.0" acorn-jsx: "npm:^5.3.2" eslint-visitor-keys: "npm:^4.0.0" checksum: 10c0/52e6feaa77a31a6038f0c0e3fce93010a4625701925b0715cd54a2ae190b3275053a0717db698697b32653788ac04845e489d6773b508d6c2e8752f3c57470a0 languageName: node linkType: hard "espree@npm:^10.4.0": version: 10.4.0 resolution: "espree@npm:10.4.0" dependencies: acorn: "npm:^8.15.0" acorn-jsx: "npm:^5.3.2" eslint-visitor-keys: "npm:^4.2.1" checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b languageName: node linkType: hard "esquery@npm:^1.5.0": version: 1.5.0 resolution: "esquery@npm:1.5.0" dependencies: estraverse: "npm:^5.1.0" checksum: 10c0/a084bd049d954cc88ac69df30534043fb2aee5555b56246493f42f27d1e168f00d9e5d4192e46f10290d312dc30dc7d58994d61a609c579c1219d636996f9213 languageName: node linkType: hard "esrecurse@npm:^4.3.0": version: 4.3.0 resolution: "esrecurse@npm:4.3.0" dependencies: estraverse: "npm:^5.2.0" checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 languageName: node linkType: hard "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 languageName: node linkType: hard "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 languageName: node linkType: hard "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard "fast-json-stable-stringify@npm:^2.0.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b languageName: node linkType: hard "fast-levenshtein@npm:^2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 languageName: node linkType: hard "file-entry-cache@npm:^8.0.0": version: 8.0.0 resolution: "file-entry-cache@npm:8.0.0" dependencies: flat-cache: "npm:^4.0.0" checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 languageName: node linkType: hard "find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" dependencies: locate-path: "npm:^6.0.0" path-exists: "npm:^4.0.0" checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a languageName: node linkType: hard "flat-cache@npm:^4.0.0": version: 4.0.1 resolution: "flat-cache@npm:4.0.1" dependencies: flatted: "npm:^3.2.9" keyv: "npm:^4.5.4" checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc languageName: node linkType: hard "flat@npm:^5.0.2": version: 5.0.2 resolution: "flat@npm:5.0.2" bin: flat: cli.js checksum: 10c0/f178b13482f0cd80c7fede05f4d10585b1f2fdebf26e12edc138e32d3150c6ea6482b7f12813a1091143bad52bb6d3596bca51a162257a21163c0ff438baa5fe languageName: node linkType: hard "flatted@npm:^3.2.9": version: 3.3.1 resolution: "flatted@npm:3.3.1" checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf languageName: node linkType: hard "foreground-child@npm:^3.1.0, foreground-child@npm:^3.1.1": version: 3.2.1 resolution: "foreground-child@npm:3.2.1" dependencies: cross-spawn: "npm:^7.0.0" signal-exit: "npm:^4.0.1" checksum: 10c0/9a53a33dbd87090e9576bef65fb4a71de60f6863a8062a7b11bc1cbe3cc86d428677d7c0b9ef61cdac11007ac580006f78bd5638618d564cfd5e6fd713d6878f languageName: node linkType: hard "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde languageName: node linkType: hard "get-east-asian-width@npm:^1.0.0": version: 1.4.0 resolution: "get-east-asian-width@npm:1.4.0" checksum: 10c0/4e481d418e5a32061c36fbb90d1b225a254cc5b2df5f0b25da215dcd335a3c111f0c2023ffda43140727a9cafb62dac41d022da82c08f31083ee89f714ee3b83 languageName: node linkType: hard "glob-parent@npm:^6.0.2": version: 6.0.2 resolution: "glob-parent@npm:6.0.2" dependencies: is-glob: "npm:^4.0.3" checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 languageName: node linkType: hard "glob@npm:^10.4.1": version: 10.4.2 resolution: "glob@npm:10.4.2" dependencies: foreground-child: "npm:^3.1.0" jackspeak: "npm:^3.1.2" minimatch: "npm:^9.0.4" minipass: "npm:^7.1.2" package-json-from-dist: "npm:^1.0.0" path-scurry: "npm:^1.11.1" bin: glob: dist/esm/bin.mjs checksum: 10c0/2c7296695fa75a935f3ad17dc62e4e170a8bb8752cf64d328be8992dd6ad40777939003754e10e9741ff8fbe43aa52fba32d6930d0ffa0e3b74bc3fb5eebaa2f languageName: node linkType: hard "glob@npm:^10.4.5": version: 10.5.0 resolution: "glob@npm:10.5.0" dependencies: foreground-child: "npm:^3.1.0" jackspeak: "npm:^3.1.2" minimatch: "npm:^9.0.4" minipass: "npm:^7.1.2" package-json-from-dist: "npm:^1.0.0" path-scurry: "npm:^1.11.1" bin: glob: dist/esm/bin.mjs checksum: 10c0/100705eddbde6323e7b35e1d1ac28bcb58322095bd8e63a7d0bef1a2cdafe0d0f7922a981b2b48369a4f8c1b077be5c171804534c3509dfe950dde15fbe6d828 languageName: node linkType: hard "glob@npm:^13.0.0": version: 13.0.0 resolution: "glob@npm:13.0.0" dependencies: minimatch: "npm:^10.1.1" minipass: "npm:^7.1.2" path-scurry: "npm:^2.0.0" checksum: 10c0/8e2f5821f3f7c312dd102e23a15b80c79e0837a9872784293ba2e15ec73b3f3749a49a42a31bfcb4e52c84820a474e92331c2eebf18819d20308f5c33876630a languageName: node linkType: hard "globals@npm:^14.0.0": version: 14.0.0 resolution: "globals@npm:14.0.0" checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d languageName: node linkType: hard "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 languageName: node linkType: hard "he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" bin: he: bin/he checksum: 10c0/a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 languageName: node linkType: hard "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 languageName: node linkType: hard "ignore@npm:^5.2.0": version: 5.3.1 resolution: "ignore@npm:5.3.1" checksum: 10c0/703f7f45ffb2a27fb2c5a8db0c32e7dee66b33a225d28e8db4e1be6474795f606686a6e3bcc50e1aa12f2042db4c9d4a7d60af3250511de74620fbed052ea4cd languageName: node linkType: hard "import-fresh@npm:^3.2.1": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: parent-module: "npm:^1.0.0" resolve-from: "npm:^4.0.0" checksum: 10c0/7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3 languageName: node linkType: hard "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 languageName: node linkType: hard "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 languageName: node linkType: hard "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc languageName: node linkType: hard "is-glob@npm:^4.0.0, is-glob@npm:^4.0.3": version: 4.0.3 resolution: "is-glob@npm:4.0.3" dependencies: is-extglob: "npm:^2.1.1" checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a languageName: node linkType: hard "is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 languageName: node linkType: hard "is-plain-obj@npm:^2.1.0": version: 2.1.0 resolution: "is-plain-obj@npm:2.1.0" checksum: 10c0/e5c9814cdaa627a9ad0a0964ded0e0491bfd9ace405c49a5d63c88b30a162f1512c069d5b80997893c4d0181eadc3fed02b4ab4b81059aba5620bfcdfdeb9c53 languageName: node linkType: hard "is-unicode-supported@npm:^0.1.0": version: 0.1.0 resolution: "is-unicode-supported@npm:0.1.0" checksum: 10c0/00cbe3455c3756be68d2542c416cab888aebd5012781d6819749fefb15162ff23e38501fe681b3d751c73e8ff561ac09a5293eba6f58fdf0178462ce6dcb3453 languageName: node linkType: hard "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d languageName: node linkType: hard "istanbul-lib-coverage@npm:^3.0.0": version: 3.0.0 resolution: "istanbul-lib-coverage@npm:3.0.0" checksum: 10c0/29ab1980e973f169d0de899256c193caff192f30e5e4f50ec40bddac307d454c7c6493836fffea633469e7d1d1ab7fe04fa64c426f8bf8d14b17679284f5fd07 languageName: node linkType: hard "istanbul-lib-coverage@npm:^3.2.0": version: 3.2.2 resolution: "istanbul-lib-coverage@npm:3.2.2" checksum: 10c0/6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b languageName: node linkType: hard "istanbul-lib-report@npm:^3.0.0": version: 3.0.0 resolution: "istanbul-lib-report@npm:3.0.0" dependencies: istanbul-lib-coverage: "npm:^3.0.0" make-dir: "npm:^3.0.0" supports-color: "npm:^7.1.0" checksum: 10c0/81b0d5187c7603ed71bdea0b701a7329f8146549ca19aa26d91b4a163aea756f9d55c1a6dc1dcd087e24dfcb99baa69e266a68644fbfd5dc98107d6f6f5948d2 languageName: node linkType: hard "istanbul-lib-report@npm:^3.0.1": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" dependencies: istanbul-lib-coverage: "npm:^3.0.0" make-dir: "npm:^4.0.0" supports-color: "npm:^7.1.0" checksum: 10c0/84323afb14392de8b6a5714bd7e9af845cfbd56cfe71ed276cda2f5f1201aea673c7111901227ee33e68e4364e288d73861eb2ed48f6679d1e69a43b6d9b3ba7 languageName: node linkType: hard "istanbul-reports@npm:^3.1.6": version: 3.1.7 resolution: "istanbul-reports@npm:3.1.7" dependencies: html-escaper: "npm:^2.0.0" istanbul-lib-report: "npm:^3.0.0" checksum: 10c0/a379fadf9cf8dc5dfe25568115721d4a7eb82fbd50b005a6672aff9c6989b20cc9312d7865814e0859cd8df58cbf664482e1d3604be0afde1f7fc3ccc1394a51 languageName: node linkType: hard "jackspeak@npm:^3.1.2": version: 3.4.0 resolution: "jackspeak@npm:3.4.0" dependencies: "@isaacs/cliui": "npm:^8.0.2" "@pkgjs/parseargs": "npm:^0.11.0" dependenciesMeta: "@pkgjs/parseargs": optional: true checksum: 10c0/7e42d1ea411b4d57d43ea8a6afbca9224382804359cb72626d0fc45bb8db1de5ad0248283c3db45fe73e77210750d4fcc7c2b4fe5d24fda94aaa24d658295c5f languageName: node linkType: hard "js-yaml@npm:^4.1.0": version: 4.1.0 resolution: "js-yaml@npm:4.1.0" dependencies: argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f languageName: node linkType: hard "js-yaml@npm:^4.1.1": version: 4.1.1 resolution: "js-yaml@npm:4.1.1" dependencies: argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7 languageName: node linkType: hard "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 languageName: node linkType: hard "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce languageName: node linkType: hard "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 languageName: node linkType: hard "keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: json-buffer: "npm:3.0.1" checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e languageName: node linkType: hard "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" dependencies: prelude-ls: "npm:^1.2.1" type-check: "npm:~0.4.0" checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e languageName: node linkType: hard "locate-path@npm:^6.0.0": version: 6.0.0 resolution: "locate-path@npm:6.0.0" dependencies: p-locate: "npm:^5.0.0" checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 languageName: node linkType: hard "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 languageName: node linkType: hard "log-symbols@npm:^4.1.0": version: 4.1.0 resolution: "log-symbols@npm:4.1.0" dependencies: chalk: "npm:^4.1.0" is-unicode-supported: "npm:^0.1.0" checksum: 10c0/67f445a9ffa76db1989d0fa98586e5bc2fd5247260dafb8ad93d9f0ccd5896d53fb830b0e54dade5ad838b9de2006c826831a3c528913093af20dff8bd24aca6 languageName: node linkType: hard "lru-cache@npm:^10.2.0": version: 10.2.2 resolution: "lru-cache@npm:10.2.2" checksum: 10c0/402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6 languageName: node linkType: hard "lru-cache@npm:^11.0.0": version: 11.2.4 resolution: "lru-cache@npm:11.2.4" checksum: 10c0/4a24f9b17537619f9144d7b8e42cd5a225efdfd7076ebe7b5e7dc02b860a818455201e67fbf000765233fe7e339d3c8229fc815e9b58ee6ede511e07608c19b2 languageName: node linkType: hard "make-dir@npm:^3.0.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: semver: "npm:^6.0.0" checksum: 10c0/56aaafefc49c2dfef02c5c95f9b196c4eb6988040cf2c712185c7fe5c99b4091591a7fc4d4eafaaefa70ff763a26f6ab8c3ff60b9e75ea19876f49b18667ecaa languageName: node linkType: hard "make-dir@npm:^4.0.0": version: 4.0.0 resolution: "make-dir@npm:4.0.0" dependencies: semver: "npm:^7.5.3" checksum: 10c0/69b98a6c0b8e5c4fe9acb61608a9fbcfca1756d910f51e5dbe7a9e5cfb74fca9b8a0c8a0ffdf1294a740826c1ab4871d5bf3f62f72a3049e5eac6541ddffed68 languageName: node linkType: hard "minimatch@npm:^10.1.1": version: 10.1.1 resolution: "minimatch@npm:10.1.1" dependencies: "@isaacs/brace-expansion": "npm:^5.0.0" checksum: 10c0/c85d44821c71973d636091fddbfbffe62370f5ee3caf0241c5b60c18cd289e916200acb2361b7e987558cd06896d153e25d505db9fc1e43e6b4b6752e2702902 languageName: node linkType: hard "minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: brace-expansion: "npm:^1.1.7" checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 languageName: node linkType: hard "minimatch@npm:^9.0.4": version: 9.0.4 resolution: "minimatch@npm:9.0.4" dependencies: brace-expansion: "npm:^2.0.1" checksum: 10c0/2c16f21f50e64922864e560ff97c587d15fd491f65d92a677a344e970fe62aafdbeafe648965fa96d33c061b4d0eabfe0213466203dd793367e7f28658cf6414 languageName: node linkType: hard "minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: brace-expansion: "npm:^2.0.1" checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed languageName: node linkType: hard "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.1.2": version: 7.1.2 resolution: "minipass@npm:7.1.2" checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 languageName: node linkType: hard "mocha@npm:^11.7.5": version: 11.7.5 resolution: "mocha@npm:11.7.5" dependencies: browser-stdout: "npm:^1.3.1" chokidar: "npm:^4.0.1" debug: "npm:^4.3.5" diff: "npm:^7.0.0" escape-string-regexp: "npm:^4.0.0" find-up: "npm:^5.0.0" glob: "npm:^10.4.5" he: "npm:^1.2.0" is-path-inside: "npm:^3.0.3" js-yaml: "npm:^4.1.0" log-symbols: "npm:^4.1.0" minimatch: "npm:^9.0.5" ms: "npm:^2.1.3" picocolors: "npm:^1.1.1" serialize-javascript: "npm:^6.0.2" strip-json-comments: "npm:^3.1.1" supports-color: "npm:^8.1.1" workerpool: "npm:^9.2.0" yargs: "npm:^17.7.2" yargs-parser: "npm:^21.1.1" yargs-unparser: "npm:^2.0.0" bin: _mocha: bin/_mocha mocha: bin/mocha.js checksum: 10c0/e6150cba85345aaabbc5b2e7341b1e6706b878f5a9782960cad57fd4cc458730a76d08c5f1a3e05d3ebb49cad93b455764bb00727bd148dcaf0c6dd4fa665b3d languageName: node linkType: hard "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc languageName: node linkType: hard "ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 languageName: node linkType: hard "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 languageName: node linkType: hard "optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" dependencies: deep-is: "npm:^0.1.3" fast-levenshtein: "npm:^2.0.6" levn: "npm:^0.4.1" prelude-ls: "npm:^1.2.1" type-check: "npm:^0.4.0" word-wrap: "npm:^1.2.5" checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 languageName: node linkType: hard "p-limit@npm:^3.0.2": version: 3.1.0 resolution: "p-limit@npm:3.1.0" dependencies: yocto-queue: "npm:^0.1.0" checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a languageName: node linkType: hard "p-locate@npm:^5.0.0": version: 5.0.0 resolution: "p-locate@npm:5.0.0" dependencies: p-limit: "npm:^3.0.2" checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a languageName: node linkType: hard "package-json-from-dist@npm:^1.0.0": version: 1.0.0 resolution: "package-json-from-dist@npm:1.0.0" checksum: 10c0/e3ffaf6ac1040ab6082a658230c041ad14e72fabe99076a2081bb1d5d41210f11872403fc09082daf4387fc0baa6577f96c9c0e94c90c394fd57794b66aa4033 languageName: node linkType: hard "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" dependencies: callsites: "npm:^3.0.0" checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 languageName: node linkType: hard "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b languageName: node linkType: hard "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c languageName: node linkType: hard "path-scurry@npm:^1.11.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" dependencies: lru-cache: "npm:^10.2.0" minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d languageName: node linkType: hard "path-scurry@npm:^2.0.0": version: 2.0.1 resolution: "path-scurry@npm:2.0.1" dependencies: lru-cache: "npm:^11.0.0" minipass: "npm:^7.1.2" checksum: 10c0/2a16ed0e81fbc43513e245aa5763354e25e787dab0d539581a6c3f0f967461a159ed6236b2559de23aa5b88e7dc32b469b6c47568833dd142a4b24b4f5cd2620 languageName: node linkType: hard "picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 languageName: node linkType: hard "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd languageName: node linkType: hard "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 languageName: node linkType: hard "randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" dependencies: safe-buffer: "npm:^5.1.0" checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 languageName: node linkType: hard "readdirp@npm:^4.0.1": version: 4.1.2 resolution: "readdirp@npm:4.1.2" checksum: 10c0/60a14f7619dec48c9c850255cd523e2717001b0e179dc7037cfa0895da7b9e9ab07532d324bfb118d73a710887d1e35f79c495fa91582784493e085d18c72c62 languageName: node linkType: hard "replace-in-file@workspace:.": version: 0.0.0-use.local resolution: "replace-in-file@workspace:." dependencies: "@eslint/js": "npm:^9.39.1" c8: "npm:^10.1.3" chai: "npm:^6.2.1" chai-as-promised: "npm:^8.0.2" chalk: "npm:^5.6.2" eslint: "npm:^9.39.1" glob: "npm:^13.0.0" mocha: "npm:^11.7.5" yargs: "npm:^18.0.0" bin: replace-in-file: ./bin/cli.js languageName: unknown linkType: soft "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 languageName: node linkType: hard "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 languageName: node linkType: hard "safe-buffer@npm:^5.1.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 languageName: node linkType: hard "semver@npm:^6.0.0": version: 6.3.0 resolution: "semver@npm:6.3.0" bin: semver: ./bin/semver.js checksum: 10c0/1f4959e15bcfbaf727e964a4920f9260141bb8805b399793160da4e7de128e42a7d1f79c1b7d5cd21a6073fba0d55feb9966f5fef3e5ccb8e1d7ead3d7527458 languageName: node linkType: hard "semver@npm:^7.5.3": version: 7.6.2 resolution: "semver@npm:7.6.2" bin: semver: bin/semver.js checksum: 10c0/97d3441e97ace8be4b1976433d1c32658f6afaff09f143e52c593bae7eef33de19e3e369c88bd985ce1042c6f441c80c6803078d1de2a9988080b66684cbb30c languageName: node linkType: hard "serialize-javascript@npm:^6.0.2": version: 6.0.2 resolution: "serialize-javascript@npm:6.0.2" dependencies: randombytes: "npm:^2.1.0" checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 languageName: node linkType: hard "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" dependencies: shebang-regex: "npm:^3.0.0" checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e languageName: node linkType: hard "shebang-regex@npm:^3.0.0": version: 3.0.0 resolution: "shebang-regex@npm:3.0.0" checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 languageName: node linkType: hard "signal-exit@npm:^4.0.1": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 languageName: node linkType: hard "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: emoji-regex: "npm:^8.0.0" is-fullwidth-code-point: "npm:^3.0.0" strip-ansi: "npm:^6.0.1" checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b languageName: node linkType: hard "string-width@npm:^4.1.0, string-width@npm:^4.2.0": version: 4.2.0 resolution: "string-width@npm:4.2.0" dependencies: emoji-regex: "npm:^8.0.0" is-fullwidth-code-point: "npm:^3.0.0" strip-ansi: "npm:^6.0.0" checksum: 10c0/54d6451abfdca5f147f930fe4eb1bbdf409ba115042146bb93dae309342124afcfeb776149075f60a6f8d6b2d3b68f48702fc96144b37789dd7a4752284b9648 languageName: node linkType: hard "string-width@npm:^5.0.1, string-width@npm:^5.1.2": version: 5.1.2 resolution: "string-width@npm:5.1.2" dependencies: eastasianwidth: "npm:^0.2.0" emoji-regex: "npm:^9.2.2" strip-ansi: "npm:^7.0.1" checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca languageName: node linkType: hard "string-width@npm:^7.0.0, string-width@npm:^7.2.0": version: 7.2.0 resolution: "string-width@npm:7.2.0" dependencies: emoji-regex: "npm:^10.3.0" get-east-asian-width: "npm:^1.0.0" strip-ansi: "npm:^7.1.0" checksum: 10c0/eb0430dd43f3199c7a46dcbf7a0b34539c76fe3aa62763d0b0655acdcbdf360b3f66f3d58ca25ba0205f42ea3491fa00f09426d3b7d3040e506878fc7664c9b9 languageName: node linkType: hard "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: ansi-regex: "npm:^5.0.1" checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 languageName: node linkType: hard "strip-ansi@npm:^6.0.0": version: 6.0.0 resolution: "strip-ansi@npm:6.0.0" dependencies: ansi-regex: "npm:^5.0.0" checksum: 10c0/85257c80250541cc0e65088c7dc768563bdbd1bf7120471d6d3a73cdc60e8149a50038c12a6fd4a30b674587f306ae42e2cc73ac3095daf193633daa0bd8f928 languageName: node linkType: hard "strip-ansi@npm:^7.0.1": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" dependencies: ansi-regex: "npm:^6.0.1" checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 languageName: node linkType: hard "strip-ansi@npm:^7.1.0": version: 7.1.2 resolution: "strip-ansi@npm:7.1.2" dependencies: ansi-regex: "npm:^6.0.1" checksum: 10c0/0d6d7a023de33368fd042aab0bf48f4f4077abdfd60e5393e73c7c411e85e1b3a83507c11af2e656188511475776215df9ca589b4da2295c9455cc399ce1858b languageName: node linkType: hard "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd languageName: node linkType: hard "supports-color@npm:^7.1.0": version: 7.1.0 resolution: "supports-color@npm:7.1.0" dependencies: has-flag: "npm:^4.0.0" checksum: 10c0/e2e6d0c4a0165790801c87b6b16f3e1e0751b4e26e0fdd3c3ff41dd00f6f933548ac3f06b6b9225c27117c386e270f77f08350e50bdef5070cd67d13893bbb66 languageName: node linkType: hard "supports-color@npm:^8.1.1": version: 8.1.1 resolution: "supports-color@npm:8.1.1" dependencies: has-flag: "npm:^4.0.0" checksum: 10c0/ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 languageName: node linkType: hard "test-exclude@npm:^7.0.1": version: 7.0.1 resolution: "test-exclude@npm:7.0.1" dependencies: "@istanbuljs/schema": "npm:^0.1.2" glob: "npm:^10.4.1" minimatch: "npm:^9.0.4" checksum: 10c0/6d67b9af4336a2e12b26a68c83308c7863534c65f27ed4ff7068a56f5a58f7ac703e8fc80f698a19bb154fd8f705cdf7ec347d9512b2c522c737269507e7b263 languageName: node linkType: hard "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" dependencies: prelude-ls: "npm:^1.2.1" checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 languageName: node linkType: hard "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" dependencies: punycode: "npm:^2.1.0" checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c languageName: node linkType: hard "v8-to-istanbul@npm:^9.0.0": version: 9.3.0 resolution: "v8-to-istanbul@npm:9.3.0" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.12" "@types/istanbul-lib-coverage": "npm:^2.0.1" convert-source-map: "npm:^2.0.0" checksum: 10c0/968bcf1c7c88c04df1ffb463c179558a2ec17aa49e49376120504958239d9e9dad5281aa05f2a78542b8557f2be0b0b4c325710262f3b838b40d703d5ed30c23 languageName: node linkType: hard "which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" dependencies: isexe: "npm:^2.0.0" bin: node-which: ./bin/node-which checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f languageName: node linkType: hard "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 languageName: node linkType: hard "workerpool@npm:^9.2.0": version: 9.3.4 resolution: "workerpool@npm:9.3.4" checksum: 10c0/b09d80c81c6e50dab1bc6cc3a4180d4222068f17ada9b04fb7053bf98fdbe3dbd6bdd04ad1420363f5391cbf57d622ecd2680469ad0137aef990f510ab807a09 languageName: node linkType: hard "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: ansi-styles: "npm:^4.0.0" string-width: "npm:^4.1.0" strip-ansi: "npm:^6.0.0" checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da languageName: node linkType: hard "wrap-ansi@npm:^8.1.0": version: 8.1.0 resolution: "wrap-ansi@npm:8.1.0" dependencies: ansi-styles: "npm:^6.1.0" string-width: "npm:^5.0.1" strip-ansi: "npm:^7.0.1" checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 languageName: node linkType: hard "wrap-ansi@npm:^9.0.0": version: 9.0.2 resolution: "wrap-ansi@npm:9.0.2" dependencies: ansi-styles: "npm:^6.2.1" string-width: "npm:^7.0.0" strip-ansi: "npm:^7.1.0" checksum: 10c0/3305839b9a0d6fb930cb63a52f34d3936013d8b0682ff3ec133c9826512620f213800ffa19ea22904876d5b7e9a3c1f40682f03597d986a4ca881fa7b033688c languageName: node linkType: hard "y18n@npm:^5.0.5": version: 5.0.5 resolution: "y18n@npm:5.0.5" checksum: 10c0/62523d0036ca408f0fa336784b003e80c9a0785dde42050c90e9208df6dafc9440c23d9defd102518ec9c5e883838b1b94615bd98446fc7dddab4c007ede8845 languageName: node linkType: hard "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 languageName: node linkType: hard "yargs-parser@npm:^22.0.0": version: 22.0.0 resolution: "yargs-parser@npm:22.0.0" checksum: 10c0/cb7ef81759c4271cb1d96b9351dbbc9a9ce35d3e1122d2b739bf6c432603824fa02c67cc12dcef6ea80283379d63495686e8f41cc7b06c6576e792aba4d33e1c languageName: node linkType: hard "yargs-unparser@npm:^2.0.0": version: 2.0.0 resolution: "yargs-unparser@npm:2.0.0" dependencies: camelcase: "npm:^6.0.0" decamelize: "npm:^4.0.0" flat: "npm:^5.0.2" is-plain-obj: "npm:^2.1.0" checksum: 10c0/a5a7d6dc157efa95122e16780c019f40ed91d4af6d2bac066db8194ed0ec5c330abb115daa5a79ff07a9b80b8ea80c925baacf354c4c12edd878c0529927ff03 languageName: node linkType: hard "yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: cliui: "npm:^8.0.1" escalade: "npm:^3.1.1" get-caller-file: "npm:^2.0.5" require-directory: "npm:^2.1.1" string-width: "npm:^4.2.3" y18n: "npm:^5.0.5" yargs-parser: "npm:^21.1.1" checksum: 10c0/ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 languageName: node linkType: hard "yargs@npm:^18.0.0": version: 18.0.0 resolution: "yargs@npm:18.0.0" dependencies: cliui: "npm:^9.0.1" escalade: "npm:^3.1.1" get-caller-file: "npm:^2.0.5" string-width: "npm:^7.2.0" y18n: "npm:^5.0.5" yargs-parser: "npm:^22.0.0" checksum: 10c0/bf290e4723876ea9c638c786a5c42ac28e03c9ca2325e1424bf43b94e5876456292d3ed905b853ebbba6daf43ed29e772ac2a6b3c5fb1b16533245d6211778f3 languageName: node linkType: hard "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f languageName: node linkType: hard