From a2a6dee025512533e68055927f78ad6e00e653d4 Mon Sep 17 00:00:00 2001 From: Hare Date: Mon, 22 Jun 2026 18:05:26 +0900 Subject: [PATCH] Show source names in diagnostics --- crates/decodal-cli/src/main.rs | 50 ++++++------- crates/decodal-core/src/eval.rs | 44 +++++++++++ crates/decodal-core/src/lib.rs | 2 +- crates/decodal-wasm/src/lib.rs | 70 +++++++++++------- .../souce/design/diagnostics-and-fallback.md | 1 + .../src/wasm/decodal_wasm_bg.wasm | Bin 228514 -> 229475 bytes 6 files changed, 113 insertions(+), 54 deletions(-) diff --git a/crates/decodal-cli/src/main.rs b/crates/decodal-cli/src/main.rs index 024e946..9809ba1 100644 --- a/crates/decodal-cli/src/main.rs +++ b/crates/decodal-cli/src/main.rs @@ -4,19 +4,22 @@ use std::{ process::ExitCode, }; -use decodal_core::{Data, Diagnostic, DiagnosticKind, Engine, LoadedSource, SourceLoader, Span}; +use decodal_core::{ + Data, Diagnostic, DiagnosticKind, Engine, LoadedSource, SourceId, SourceLoader, Span, + format_diagnostic_with, +}; fn main() -> ExitCode { match run() { Ok(()) => ExitCode::SUCCESS, Err(error) => { - print_diagnostic(&error); + eprintln!("{error}"); ExitCode::FAILURE } } } -fn run() -> Result<(), Diagnostic> { +fn run() -> Result<(), String> { let mut args = env::args().skip(1); let first = args.next().unwrap_or_else(|| String::from("--help")); match first.as_str() { @@ -51,12 +54,19 @@ fn run() -> Result<(), Diagnostic> { } } -fn materialize_path(path: &str) -> Result { - let root = read_root_source(path)?; +fn materialize_path(path: &str) -> Result { + let root = read_root_source(path).map_err(format_raw_diagnostic)?; + let root_name = root.name.clone(); let mut engine = Engine::new(FsLoader); - let module = engine.add_root_source(root.key, root.name, &root.source)?; - let value = engine.eval_module(module)?; - engine.materialize(&value) + let module = engine + .add_root_source(root.key, root.name, &root.source) + .map_err(|error| format_diagnostic_with_root(&error, &root_name))?; + let value = engine + .eval_module(module) + .map_err(|error| engine.format_diagnostic(&error))?; + engine + .materialize(&value) + .map_err(|error| engine.format_diagnostic(&error)) } fn read_root_source(path: &str) -> Result { @@ -139,24 +149,12 @@ fn print_help() { println!(" decodal - Read DCDL source from stdin"); } -fn print_diagnostic(error: &Diagnostic) { - eprintln!( - "error[{kind:?}] {source}:{start}..{end}: {message}", - kind = error.kind, - source = error.span.source.0, - start = error.span.start, - end = error.span.end, - message = error.message, - ); - for label in &error.labels { - eprintln!( - " note {source}:{start}..{end}: {message}", - source = label.span.source.0, - start = label.span.start, - end = label.span.end, - message = label.message, - ); - } +fn format_diagnostic_with_root(error: &Diagnostic, root_name: &str) -> String { + format_diagnostic_with(error, |source| (source == SourceId(0)).then_some(root_name)) +} + +fn format_raw_diagnostic(error: Diagnostic) -> String { + format_diagnostic_with(&error, |_| None) } fn print_data(data: &Data, indent: usize) { diff --git a/crates/decodal-core/src/eval.rs b/crates/decodal-core/src/eval.rs index 6220ad6..dc52280 100644 --- a/crates/decodal-core/src/eval.rs +++ b/crates/decodal-core/src/eval.rs @@ -87,6 +87,17 @@ impl Engine { self.materialize_with_path(value, &mut Vec::new()) } + pub fn source_name(&self, source: SourceId) -> Option<&str> { + self.modules + .iter() + .find(|module| module.source == source) + .map(|module| module.name.as_str()) + } + + pub fn format_diagnostic(&self, diagnostic: &Diagnostic) -> String { + format_diagnostic_with(diagnostic, |source| self.source_name(source)) + } + fn materialize_with_path( &mut self, value: &RuntimeValue, @@ -1163,6 +1174,39 @@ fn primitive_type(name: &str) -> Option { } } +pub fn format_diagnostic_with<'a>( + diagnostic: &Diagnostic, + mut source_name: impl FnMut(SourceId) -> Option<&'a str>, +) -> String { + let mut out = format!( + "{:?} at {}:{}..{}: {}", + diagnostic.kind, + format_source(diagnostic.span.source, &mut source_name), + diagnostic.span.start, + diagnostic.span.end, + diagnostic.message, + ); + for label in &diagnostic.labels { + out.push_str(&format!( + "\nnote at {}:{}..{}: {}", + format_source(label.span.source, &mut source_name), + label.span.start, + label.span.end, + label.message, + )); + } + out +} + +fn format_source<'a>( + source: SourceId, + source_name: &mut impl FnMut(SourceId) -> Option<&'a str>, +) -> String { + source_name(source) + .map(String::from) + .unwrap_or_else(|| format!("source {}", source.0)) +} + fn constraint_primary_span(constraints: &[ConstraintEntry]) -> Span { constraints .first() diff --git a/crates/decodal-core/src/lib.rs b/crates/decodal-core/src/lib.rs index 25504ab..b81c058 100644 --- a/crates/decodal-core/src/lib.rs +++ b/crates/decodal-core/src/lib.rs @@ -17,7 +17,7 @@ pub use ast::{Ast, BinaryOp, CompareOp, Expr, ExprId, Field, Literal, Param}; pub use constraints::normalize_constraints; pub use diagnostic::{Diagnostic, DiagnosticKind, Result}; pub use embedding::{HostField, HostValue}; -pub use eval::Engine; +pub use eval::{Engine, format_diagnostic_with}; pub use lexer::{Lexer, Token, TokenKind}; pub use module::{EmptyLoader, LoadedSource, Module, SourceLoader}; pub use parser::{ParseOutput, Parser, SourceForm, parse_source, parse_source_with_source_id}; diff --git a/crates/decodal-wasm/src/lib.rs b/crates/decodal-wasm/src/lib.rs index a67d12f..bf465d3 100644 --- a/crates/decodal-wasm/src/lib.rs +++ b/crates/decodal-wasm/src/lib.rs @@ -1,7 +1,8 @@ use std::collections::BTreeMap; use decodal_core::{ - Data, Diagnostic, DiagnosticKind, EmptyLoader, Engine, LoadedSource, SourceLoader, Span, + Data, Diagnostic, DiagnosticKind, EmptyLoader, Engine, LoadedSource, SourceId, SourceLoader, + Span, format_diagnostic_with, }; use wasm_bindgen::prelude::*; @@ -24,11 +25,18 @@ fn encode_result(result: Result) -> String { fn evaluate_inner(source: &str) -> Result { let mut engine = Engine::new(EmptyLoader); - let module = engine - .add_root_source("playground", "playground", source) - .map_err(format_diagnostic)?; - let value = engine.eval_module(module).map_err(format_diagnostic)?; - let data = engine.materialize(&value).map_err(format_diagnostic)?; + let module = match engine.add_root_source("playground", "playground", source) { + Ok(module) => module, + Err(error) => return Err(format_diagnostic_with_root(&error, "playground")), + }; + let value = match engine.eval_module(module) { + Ok(value) => value, + Err(error) => return Err(engine.format_diagnostic(&error)), + }; + let data = match engine.materialize(&value) { + Ok(data) => data, + Err(error) => return Err(engine.format_diagnostic(&error)), + }; Ok(format_data(&data, 0)) } @@ -48,11 +56,18 @@ fn evaluate_project_inner(entry: &str, files_json: &str) -> Result module, + Err(error) => return Err(format_diagnostic_with_root(&error, &entry)), + }; + let value = match engine.eval_module(module) { + Ok(value) => value, + Err(error) => return Err(engine.format_diagnostic(&error)), + }; + let data = match engine.materialize(&value) { + Ok(data) => data, + Err(error) => return Err(engine.format_diagnostic(&error)), + }; Ok(format_data(&data, 0)) } @@ -124,22 +139,10 @@ fn normalize_path(path: &str) -> Option { } } -fn format_diagnostic(diagnostic: decodal_core::Diagnostic) -> String { - let mut out = format!( - "{:?} at {}:{}..{}: {}", - diagnostic.kind, - diagnostic.span.source.0, - diagnostic.span.start, - diagnostic.span.end, - diagnostic.message, - ); - for label in diagnostic.labels { - out.push_str(&format!( - "\nnote at {}:{}..{}: {}", - label.span.source.0, label.span.start, label.span.end, label.message, - )); - } - out +fn format_diagnostic_with_root(diagnostic: &decodal_core::Diagnostic, root_name: &str) -> String { + format_diagnostic_with(diagnostic, |source| { + (source == SourceId(0)).then_some(root_name) + }) } fn format_data(data: &Data, indent: usize) -> String { @@ -237,4 +240,17 @@ mod tests { let output = evaluate_project_inner("main.dcdl", files).unwrap(); assert!(output.contains("\"port\": 9443")); } + + #[test] + fn project_diagnostics_use_virtual_file_names() { + let files = r#"{ + "main.dcdl":"let dep = import \"./schemas/service.dcdl\"; in dep.Service & { port = 80; }", + "schemas/service.dcdl":"Service = { port = Int & > 443 default 8443; }" + }"#; + let error = evaluate_project_inner("main.dcdl", files).unwrap_err(); + assert!(error.contains("main.dcdl:")); + assert!(error.contains("schemas/service.dcdl:")); + assert!(!error.contains("source 0:")); + assert!(!error.contains("source 1:")); + } } diff --git a/doc/manual/souce/design/diagnostics-and-fallback.md b/doc/manual/souce/design/diagnostics-and-fallback.md index 40323b4..871bbf1 100644 --- a/doc/manual/souce/design/diagnostics-and-fallback.md +++ b/doc/manual/souce/design/diagnostics-and-fallback.md @@ -20,6 +20,7 @@ DiagnosticLabel { ``` `span` は primary location を示す。 +表示時には `Span.source` を source id のまま出すのではなく、可能な限り file path や virtual file name に解決する。 `labels` は同じ error に関係する追加 location を示す。 合成や materialize の失敗では、衝突した constraint、value、default、または処理中 field path を label に含める。 diff --git a/site/decodal-site/src/wasm/decodal_wasm_bg.wasm b/site/decodal-site/src/wasm/decodal_wasm_bg.wasm index 25635b8701f4c7917b845f7d1d7634732fe0c0b9..738740072070a81d56055e37f749ea0e6bb6a0f2 100644 GIT binary patch delta 29209 zcmdUY2YggT*Y}>echhzgZXkq&1lWWCK>~zc1uoK56nJciD4?PekR~Xo79bHCZfWk zoK9Ut0K>JcCZe*{SEO3AL|yBsC}V|cwJcMMr4Z{m?NH1hQJ~}79lG@H(5qw1p4~D! zzS7I_xz$8(p82C5-LBm`FL&zt>gyf5w(HoZd$*pw9G6AG`;e6#W3~ISRUC`-@MS~} zlU&aY(DHPz-rqS@q2;K+G~}K_<`11x@&C2 z2^}2|7a7JnYr3me5A!_@HT0i*5_ZkG#H_#OCg|N9=xEO3_2Smlk|HU9E< z7^XTjw=jt@#!5{zFjE^xIxrJ8vYC1_!r}1uFwA;6x>|&4t2)n_8C{L^6XXuJmK87k zaUnPTkP}(xU7}6anb@W|yJMc<*J80dXj9Ia*q#7#UW`j38kUn8-%Zf7ITsVMMdbH9 zcBs;FNXxF5?2kl-jZ{ht$`9z3!T!o%K`es(}IMtl3 zFDoQR11&Xs&vE~t};u=A8AbV;EFkrd0qSBkbuB%n93c4~XH}%2WD(8R??^kK< zgU?pU0z9f}OCS7uRffk`YvqG)R!gD%IZ4$|5Qed+YP?mV<^mAAt!7=?VmWK=$NQmL zwb3TF_WN|(vTDCZe_DUlehc`nb(r+gb=uHS>r|Z~Sca~3-DC`Px^)*O=*~zcD2?;h z$cKCTMvJY-jA&JFO7s_)8FLKv`hTeyajTx65w~=ANMN>R|F60DZyE8dRk}eDU-wTp zxXX;a4N61}cCwfXb1PP6fHUWIgQ+ppJ7>x>&r#+~-QhAFoevp6x`n7N$`W2JYK3F$`gv1;L0A&qnXEsZFU%{Fn`s52SHc*yTurucyx0q z(2YaE{fBSPv}gS9J8}ngbRV(#3iA(oU)_k{jQt#*o@>t ziq=_eU#c0oOfxRB$v6PaAZzAJ577{7$4eg+ysfi|U~8orOQ8~s+c|C9Jxb_sUi;Q` z(z?^WWXK)e6K34DQahAz`z#Una@BgOLmRqdE$fgNIl^aLc)Xvj?>ii%!PbhG&(UAj z^jBg%`E3a_^<7)S4Mte|Ua1zPY>5JOcbLmEJC?M{cb#l~`)Z3An3XW5(P?gTu*EYn zj308UcZB)al+*gPH`%g`>D1JUe4{GfTEEsbXT%$@8Jlv(bV8L8){2ZX^sF_t^Aa%e z(Jrm%t(+-c!ikpU%zabYl<00vG2Q38P2_1n4fxr1vs+Jaw_Epaj90dU)#dG+v)$it z+MCh0r2DXtwpjQUy+5SGM)<_ym|A1rzdpg46hPb~hpTu)C*<4E!J7m7KawRg*{=Zd zZ-?N{a<06+F`V+ORs9=h`gZF*8{j`_g5tq@-~pQEKeZ1GSMP6BRiMIss>PGwDFijJ zhZ)&BXU%}_BHA~HFrc#(+Nv@5<>L3X1c&Z2%<>Md4fXlk;5nhx){>*T(S)4P(Qi8e zeDLwx^s4p8$F-%_Evbk6E9eHA`qXG}tm%V$&u{-+r&KvLzb$0#?aUsh$F zVD`+8D2Sa^GIOvFH!srTHm_}k@Hq{@q~Kc&YYYno_x}R0U|3V|K!#O)UBSZ`4&ibq z=F2^fW=tq!9G+0d7}MCDa8wt^ggb)S=c;b4oi!sOTTK^!+K`+MvtJ_0wsPl`qtVv6 zImPkmnp=Ugb863RK(xksZ{FjfE7{guBCExMV%C{??B|5ee^D$KR>b_`*5LUM1F?C2 zx40kShPYT@pmTVD6>C6FRk)6iE~t+xBNn`h&kGCQEHqAI`>mP#pkQFcK*u<%>%teH z7rtJYP&Hcn_3Px;tYeF+TDum7MsWn9 znFq8C<1caxpzBzR7DqrKu3p>$^@}Vi=lTme#U5*k^~937t|bsB&AbM2T4UW>@+!|} z)PlI2_m+OdvyNEaxR^3M{a0c9RC6sJO2?oLs5Wj|U6yyGan?7>-@<2;?7q?CH12N) zh_-8-wf1E9rVCb+6+h7}YyGFQN?*=`C!GXeAJfx4IvWS`jP->rL002~g52q&92hHA~Op8*#NkCILr~)jF`T4*-EnQ-cGs2#Te}=zWqqk&6 zj0nuo8nV6>owB}P|6gOAb$R7;IR`&mO#c^|XZ^CK?muE(f*mYDdx9NUX7~fVY`oyZ zauPT7x`&lhH~&wvGIncj#6GA4CXqe`T;ac`WDzVo}8zU#a9 z<%9LT-{ym(zR3sY#C>~_il1YVGcr8xh7OO>&|xsFfM^DCO6@O5uPfCz^`dg2Kf}Xz zuXZpZ(L5DET)GTIb#uXQ{u&DyQNuijhu!2FHz{u}xa3Ey#TyW(6vCSRT~V=0vu1o3 zPphnb-<z9PRsxM2B;#9QYR%U?+rqWpfgDn3psDUU4{w3XI=j;m zD!JQE`W%BjxXL*iyx?;zJ~^qh7U*HtsG|vG7TNU}q3Yo!P}}yGhr*~Ud z7HRAk4?6x5S(^`eC}_UJ@1O6g8OZLO#e7S;x2jj{e76ywv-offSw~JTwB9%}&>;Zh?s+u+KXlyWZRONreoO+yn1EbY+kbLv;+zjHE z>f+z=3%10^FJ$D7jVZLxo?sB0j^|7~wUJ8D(uSU)7)j4qI=F_GYA))Z%kd4I2HlvU zIjjn2$`Dyo&m_PEu02y0??0U>M>BGw&LWFR*7N5QxSAcf@rvlinw-Js7IRtpg@kxj zrW=P4ad=pxhq4hg*68^<&RK9Fj1VBKxHui3EiZMU134Qm4bqx&5FX)SV|eT^mYG2} zfLsRD25E>tCVEE(M>p(aP^RkDR3tTn! zSj+zG!nxRMvuVDy@mePRWYxdk9hmIvl@Rp)biF(swT!=-g$#plV*F&i^jBk4ne$h( z$UQ30hww4Q;o4|j|Ep|^V=x{tAI?Xe_y9!Ud!SYuZ*}l*i z>tSXOQA+_A!A`cKg3(`CJ#Nf}CM$9?IdePtdp>|n5dQ1agu930<}Iy4Y`h@*mmE@E zsBz1R15`t+i89~5*X#;*u~t?%YG}=DTA0YXNb9BZ%Wz-+O~E@zbajCot*0oDR2|-# zZuYmgvhJfa%i4dlQW7}IVu(uilbyqFgdNzbcPsT)l6C1;M0^aoQQW{Pm^(jF)8^U! zVRgAx5|bT!t7*~Cg)vsQ`RJdmVkY+2yz@gDxx?^OrFydT7wBzgji49ek^l3 zFEj?QakqRt4}z3irhIUJJ$R(di014bIE-1s&-v`ToEN@4wPHLvLnn9h3;qS+PBQEA zX9J@hD%ljOY{*n!a33^yDue^Mdwbgd^`VqM{_=gJWU3qj=FhecqCgpCH7q=f4kHz* zOuUhitoutm&a&EC$c|d3APSYkItx1}6|(CWLP)%wvVSlu8v2A2}lOMn=Edj=F2r4Mk#;@ z3As5C#zfW(UwOgPPy54-4{YFk7SGPDAKjjCPY5KFH?r;tRT~+T<63i6EqU5SCCVP>*a=n+jsYGqKF2^et18y&V1;dD zPkJl4>5dMvD@9XTt=xl>8zI3-nY-B^?~oWeLs9u#$bPZ(E1mUrEJ7714k{R@IZ6dz zS&tY}sbJ0cSuTzvlYW-x<7fdbkQ3u6GyJCRM)c?~hgvf~FC;4!rR{WF-Y7~L^i)bP4hcZ->;&4chwPXILw{OsEJaUJ8yQua(i$IDC@on> zmeZK00xxb|U3j1_gn7h>WKrN=X94SIO-~kH%MTflY%YZl< zA!EwYOVpYvdyShYqLwpJaq_RSWX7~slnvj=9s9@ig0c=oC*_KAlx(|O)xtPhjma=Z z$>=nSrOV#bG+Iw$gwE1iN`_aUy7ZQ;Tb{BQks>21QZ*0!xez6-JCqZud0?^J3UOE= zWV?!#M7QODic~ZT&Y;el%=QQ6!irQkdZos4!ZCIToQyDIs=Qi}%7C)s>68?CmhDrx zQXyA0nLAGumU}8w3E4lLDxywyI>hp__h>r3Oms(nUY%;1pa>xmGDpWg#f;%$x!Csq99Cq8cDy{IiUzLT?qgqYeZWMev7i$+1|$jq zPJ4LPHROyMRJXv%`={QKhUc5}a5=FiHKb4E!J1T-HcPD*b)?s1r&`oF?SOy}5@ODQ z#uOgI7>NaE0Ozoa*|$K})n)4D&8e7OZ}~$lN-eIcOhSDq$OUMdDwYu38r94=E1COnZ}*b{-8Q#=e|w~E6m9$A$eCuLS`TB5UOB3ss>M&Vcn*vAl4 z$Z2)Rlbp@sU{{619_T=k!rj;%6qmQ^U=5DT_H`*8t3IwSU7%NG|A(nQz3R<J~tC>6SFtXU)R#q#_*eX9UA?2USn~kZKykSzIn894<1RE|7=)_V*K(##Ch>C~U zC30^=ikIygQUcAB;~t^JSTggqfgyQNo2vfm;vZFym%ShH4^ccnQGYW){KQ8728pry zKOE#kyUp=t^!I}ljUZ2iuRorBA!#(G#s8kC3G!lNa@&k;o}c^&@ieI!csjYsUHbn4 zPgR?grgz)?1IDU0%L8rxe$Ii_MvK78{R5_|0lsLah&uj{nTl40BU zA=x`1g*kG<imp@{RcVwI9R4o45y~SZ%>_+j}=Ja^vg5?-2-5kCX zoy?S{np3?7=bP?HMYD$79b>(XxvL z@=Brol0uOV=SUc-8MBZv6n>1E4*wOt27loZgumia6m&Bk%CItm{i zD(}#f^#o`+gue;KOkp2NVy?akk0dvS;JGJ*vz*FH&oFOdwBE|)~HMwG-KAYlvp7E>Y@SG$lwrDb(jW)>w;D@>@*XGh%gq*GiVd`tADJh z=cr`6e=-*H0FFF6rTh_RjQo4LY<`)i?LkJ$vCmOrWU~`y1`=%n;?y42@O-JNoUBW%Q^9}W*17pdLo}uDR z!7GP(HqaYFg}?9Z!JXamcUDYpYYhRM7z!*Br4s6h2Y3ZxNKUjxm&?2bU!+7qhh)Welnk5n zuXZ#yGz+!D;A*4C#`K2j3{u&?J+-nSyRQ+dFGLV|-tXH}w4gQK(=Q`*p*1oUr(1N+ zd*D@yrphXT`q}x-4l~6(hKHREy~KzlbNmG#0-JoV!<@rlo=kWR6FV&Tzee*YPrm;; zoVGl<vzId&6RI- zqMo?PAP;wf2fSa7&7jBV3wbDm>ctIFw_nH@;zVbB8OQiWL(^fhQfEq`E%MpUbdY|L z>0PJ@JhWzAz^rSsa~HZp=Vj+NsS~Q~f0IVgAla@fJwd;Cmv#jUd|6w6;FRa>+#L-o zs8m*X01Lr`7o+=Oj--M?@25TBs8erQ^ex(DKkCSoUep<@Hntb_gG(RP8$;7f@1(bJ zEs5TgX?;M^OgXU+HPW+@x{zb~!YXW%Tl>-r9^_QvpF$oH;in?2iianO(Pyw^%7@{L&3u=#@M!oR!miEswKnLo(1!JgvHygJaZXNq4{_XPdGtMs$K(2YG`@&r zHIxQ7P02QYq=KoNy>s4&Oi*9BrXM{{2c-Cb%7jdXmV@(F@dK)vI*^Zip{C7jJ|ZMT z!D!8w&lvp?Z&+arlw&@i!eIW~4kC2ZUr)J3o<8~3M2 zX|Ej9pSHLrBAVvQd2Zvnd~pE9KXZx|T^N)x^t}oxIn5Ntr;AXkxTg1HWC%dqXvDb$ zG$=LJWL36|-Q7XvvZg70Nxa6eP#4WP0QpX1=L6ek?RVBd^Wy30S5cF#~s zJzyvvnNy0oaoSsHApJtLTE-2g;dsm(Onvc47()BtE?ydfDP?$T4<(K8tT&8)5?J}9 zkuX9^^x_Y1fkRr5@Re9j|9{K7=&;V1s)=1nc8r05py#JI{nPi!JK7U5-Sk4 z=vsg`ZX2N^NPTw#rPt!CIVcWdID`@t4>NvNnR_fULi|&RK79pI299kPOh3tr{H2wn+6WvlDSzF8#k0Z=)1PV z;l=?y0wvZSh%Il(3n-9Yz43T>9(_%D-mv+|yM!EL_a;wXTR;_)v(-D> zu_&-MHweN_Tm^X_T}WNE#!3NUgJzhSNLkuk>}4RTiSdauiJ6U*r-KCsc{Wx%WUQCdmO-WOk~^0n z>N_WmeqP2Mac1{dub- zK`>YzoyI3#S2opk7F`1gjPMn)y*y)r)JgRgTPd? zyQmpoQL-M%SAF`6I+U*|nm{42X7)F^z)f_!3A=ZWds@gN7%ZlRM}yDVP-_LB7d8cC z3>GqM4V9#hGHnf2DX6Hy>^01Y*=4klJ=TyXaWGQ}H4{AKDIb+`=^9FLaZ513X963>hOomFf-Lys>vr$Q(M{JOW`zEj`Y&HQloJs!hQgP;5Zcob3TK4 zFv$*pp+fyxlYVQdOo62u)-eQ{6&hGGrpcVOv;>}S`*oBH`A=F;lj5QOggL}csnz6F z4&|^MdeQsMdRUW!O5(!I_tAy<*-faVJQ@EPjq~F(gYchyMjzRRldrw{DnGvgsgXQ6 zbOYgPyxg>bVvC&DjJgnp(DIHjQ?UCN%IVCl^1=qHLNjFY=Tt84ByyoIkMyDRH+b%MwZAf^+a&!a6vBooa&bQOiRKH;5`^WBhly^0Eby>02V^D;}el^ zW41IlQWyGN_S;Cm+OyH~&GPMB|15QErMnY~-$WzrS@QKD-z-;dg0SbwA2-o5Fm}{t zdZGx^$OkZv0vI%)t!{ZQZ6uskxcNxdW zyakwX7v-q!R5x}rGcE%6hl6>vOdi>;c=Y(!^sX4J$*;bqu7$@EUnkQ{XLSzil<*r~ z`B)xRCa>(5hwZUO&dfu*u`+50G|VFT#tzD(9NFM|Di$_r9@a9=xGbOFiS*)DIdLaF z9JZB_#f|0i&`xOWDWf!5_zPGyzQG5S!Ibg2-Av^k{FkSHm$J-!lLsE1!llF3#pO;=0dnr8 zq9uwHAGw^*hM>{ebg2e>HstHX*3`y1_BLU!&hryF!wb;EtR7jGvq>KQhB~vbKl&}A z46hvjEhO42*M5tzK*~4vQFGcTSMMVa&6eNo!v@_g3-70Lh)2x*R349R`>7PlChVv5 zqElepU<(Mh-QeKzc@{}0p^jzgnEQ1$1$eGbu= z1ch1uM_N0W#>=!Lw9d7W4WM8(pCd0F zp(NLeAVlKPdl1bS@jL4hUz1*p7#`Fl>nN4W%+bMr93_xBekE8MVXR;T){@NWK?wLO zWG-NY+pd9cO_8~Z5m7b*9t)Y984+e9IO}76%?Qm#aEM~=WQ1-bpkiAgvSy60S2zr0 z{>X>|b`^LSWS(P0q>TX2$h^)7-?(5C1dQ)x;sZm=DaU9L_}%0<&8!;CZ->qA2Qk}` zkJ$-7(O|faSwGQJQ1e%Qq9%aqoS>%xjXeQpca21Vdx#t8z_cikR34%fJ7CT8o zbI-*wIwDp$Vi2@)zfz+JmAnDQnBwjGD?)V2kmF9#JDC|gl`ve0!p3pU(nzo-J_ci{ zLla})vh9KW<+CT9&wDwE7Kc|vbm#eQ7%DVE1?Z9nJY03$kN^b7pt`7OBdRJyA`t0z z{WLsa(^43p32EgcMn1nn?|jn0M`h;OA&?oJ{R@~MRm3OV7(2#{>w?2xyx}ry5{!Tb zBhWaKNnz@6RgVb`q7L*hS)hU+JT^#HV>5-BOe|lv0Bv})&pHCcfG%|{WZwg+Ve(i@ z+I8$}C72iJ_UL6rvl<#Vhf9d;T?$-pm5+M^oK`yu_X#>a4?IQ(9gI_s(MTl!R;x>rUlhL4`8;YxxeJ!h7^OBqKYC zxJ;L&k;cNa2g0MwI7dr0RpFL;4KUeZW~!cb7D)7LGahyZcdq`)y8Qg#UYAS| z_`rqv@2-oVwEwU!JpKb0=Ks*TRQ$Vz`I~j|wmL_;C_h=_C>y61k48evA|`|c0P1XP zz=|W|$bmG@FtBIYbs2a8hael|x(n2<9$Las@lM{V5>uSiz?~exR~Y8qX@mRngC`Z} zefA@C+{LIS0`OutO;$hyB%Q{>PuUZxUah>*r_IJVv}JLJZ@4V6wSYA-vmeAeRig zDsLe%yhiT0MU|r^zDB~^4y%D(A8I@$3*4r5bVhc&O;ZcuuCbbC2yf#sc0O^};tuTh zN!jxbwTn8asqfw5)=Uf6N=1#grP!yXlXtummzjw3b=Up?79mAI?Pa@n^XD9uI7UV z?+G44G87r-|3uo#xyb%Pj7ukW22qLS?;8bTNsDq*^+4UiX#1TclJACy60&uO zaQiF3klb4VH-_cB5P@Gj@E#8lVH%Dq&V-9J`au?n5Dn=EZ<`3whmb@1)+Jg%-b=d0 zR(OD?+@dC}mr0SLFp^_6B1JXG=9`hCq$_tBcD%@v@kiZxhD@x${!HQV%LFD1Z=seoI zgolwO>lOivzLweXq6s+lXFRz7TM;oM_7XZ}C5rPeTqkBV2fgE!^W(%<(Ov9eZu^J1 zEi>aqy1$oIUi8vXgp6Y9d&~NX!c%B3f2ltLUo&Hx`NoT}*V{8u44|;{^FR&Z4B+ycz&GDrb)gj);ki zU~o(D!uF26pKGXw2hLCS>P6N4PB<;eeDqvg)Di=QELB3hpQ(aeL`=d=HjZef0}&QX zk1!8A{2+oQfm=hqLQs#O%?}|=63_>}GSDs%ruiU{E)W{|AQe!C`ymjn^reCOdPyGP zHU1b3V#DC=L4Wf8k>flfM&5)dMt&Y#B+Dj=uaN4yoFo$cr-W(dq*3blGcg(a`6c;L zvglJ)>F#3(pt~!WV-Nb3d6tdXgNLo%^VRUyE-88wb(7gC*ho)#zf2Lwi7v^RWkd=L z?9S4nc;R(Aye?=64$D|{gy}FgOe`a^aOqCf+xYkOHlki@*(z0(f<(QO%5v%bJXJhO zh37g&1JjM*^QxYVOP{#1;5ICo_>fqHc>k-1L~4OuDhGpoiS$9Ju}r#xFhd`3sS3o43|RCXk9QFy?Ks0sm466Y}G zP%I)R1~{T%G`8uLbWy(IgR9@>_$hyNmLTJ}w`C=PUmQ6p->)hjmF_Cw*LSjV6_JU9 z_LWt{c3eF~$>DS3Ckk%`JccLQQ_$!oQ>%#?A%~&+;XmxG1|2m? z{!vXNJvL`c1CL(bf!*1wBF*`#LC;NQSTDv1U~pdm7>3~LGqj~aPn>XOKBmr2+$!M@ z)(Px0W0GuNU3?4p0{9ghp5_jHO{!JW?I8oo~7FZ@96%44;~jpCBnFJUey<=HJC^pw0_NA#nQ zW%|S7Uvhh0@funD{yLUz(!*kY@2k0QqNM%z~#NSh4Lr{g~O+MCmTIDo2+MMzXTW5T%POlZ3VaB5v=%9)= z!nKkpl*3++G&_qTq3{>5qwkVdSSCIqB4C!vJR-V4!;F6f`**(F^hnT7#~n&YhuZ0B zGNq9yN7H1>MlgEI<-A4$KSCl8H4?A2@}2j4u=v=Jd}f0HyDDEbP?1+ne&d)r6#LQ~ zfa{)kOIJITE3mVSO$Zz!60U-)8y`0oRp3-4ydcWR^Nq3j*2qFlL|Ht#zW}|sMn2U< z)QTL6EshvD37Wzuf646RnfE%|r}5FC{Nm<>6-H z;|C$D$=pZ9$f#f0K7$}941)2aZ2g#62_@%x92#JQ{P1zyOWnwi#ngX( z^ZMSvx8ZV2b4=qm`Db(SsQoKCvhfpQKzJ_HH+vAj$=y$gCo_-xU2JfImysRxp962F z?Kf1vi}TfECnQiBsF&<8)?-r{!=0)#R5}yr49<&dCfT{PbUPd3kW-%&FM-M%Pl~UK zU*UtcbaT!^XcA?=wlczFu2Kkjtc9q?neiemg;~U_B`HtTmjPi*4~68F-C9D@PfBk~ z(UDbcyb^YAm+CBRzn;VthP{E!y@@d*dqV!=|Jrpm)$ zT~guT`x3^f8OBP^19NiK%-RA5A!RF@J`EH7g6#6NXa>!*`e|_laytGQQ6X|rJ~`d} zjEF7wF>d>DJ`UCcdBbFll}U(SaGjjk;%oK1F~a2KCZZ6;IOSO}hp*pke@-OR3VH51 z(H&cab(F9WwAF`Rxh}`G7NrVZCDDL)MhuUkti&0)y|qX%Mxv#SgJhF&N?vI#l0)X$ z2a1W$i(0sg_U!Xwj_amv7s31->1-p)B;Q4RV}B1@ly~qwEi#AYKw}Hc|H(Gc2w8Ga z8<7D$a-j{>iQ2)O820Vjp)ZKhI^RT+H{YY8vQk?Sk6&c~7mX3JRa?;JCBY!) zeDiY@@^xS{-ra$7K92)ucV&g!&U~o^i~DZki{%9d-R~r`P{o0qiGy=}PVyhh)%N@Y za_;;cIsdwcp8o~p$aNiH(>|0xb-;>#C=0wS%7u?(zTq%*oP6YE=-3^y?DJFd`&Y!n`0haASD_Mb%ST@ogEEIanCIZL3AshK&_fCQ{5xj|f0AJ$yy_2Y)v>z@rjHoZy3e#9t82p7n zl}$sKnd^NjL%0Y|O1sXmfVbptoy92oTn4U`N=l6EBC2L`;-MRqsnVflP2brDcitLV zU(rBQ(hrs8urK9lW-~rQ&=J%kJb~g(VY|!_EU8D}W}eDfFk!$Tw~cnngY%tJMl@Gdz1xIYS2&Tnv$`As%>Q@rTPvUey{$S%3yO_9tNaL1eC zDVzp-x{B7w�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 delta 28393 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