From b2d848ae2a6dd8bef3b6cbf4e193db4545453df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Hatcher=20Andr=C3=A9s?= Date: Sat, 1 Nov 2025 19:32:49 +0100 Subject: [PATCH] UPDATE: Adds a bunch of mathematical functions (#496) --- .../src/expressions/parser/static_analysis.rs | 28 ++ base/src/functions/mathematical.rs | 319 ++++++++++++++++++ base/src/functions/mod.rs | 83 ++++- xlsx/tests/calc_tests/RADIANS_DEGREES.xlsx | Bin 9316 -> 0 bytes .../RADIANS_DEGREES_and_mathematical.xlsx | Bin 0 -> 17993 bytes 5 files changed, 429 insertions(+), 1 deletion(-) delete mode 100644 xlsx/tests/calc_tests/RADIANS_DEGREES.xlsx create mode 100644 xlsx/tests/calc_tests/RADIANS_DEGREES_and_mathematical.xlsx diff --git a/base/src/expressions/parser/static_analysis.rs b/base/src/expressions/parser/static_analysis.rs index c198a47..a2af299 100644 --- a/base/src/expressions/parser/static_analysis.rs +++ b/base/src/expressions/parser/static_analysis.rs @@ -848,6 +848,20 @@ fn get_function_args_signature(kind: &Function, arg_count: usize) -> Vec args_signature_scalars(arg_count, 1, 0), Function::Radians => args_signature_scalars(arg_count, 1, 0), Function::Degrees => args_signature_scalars(arg_count, 1, 0), + Function::Int => args_signature_scalars(arg_count, 1, 0), + Function::Even => args_signature_scalars(arg_count, 1, 0), + Function::Odd => args_signature_scalars(arg_count, 1, 0), + Function::Ceiling => args_signature_scalars(arg_count, 2, 0), // (number, significance) + Function::CeilingMath => args_signature_scalars(arg_count, 1, 2), // (number, [significance], [mode]) + Function::CeilingPrecise => args_signature_scalars(arg_count, 1, 1), // (number, [significance]) + Function::Floor => args_signature_scalars(arg_count, 2, 0), // (number, significance) + Function::FloorMath => args_signature_scalars(arg_count, 1, 2), // (number, [significance], [mode]) + Function::FloorPrecise => args_signature_scalars(arg_count, 1, 1), // (number, [significance]) + Function::IsoCeiling => args_signature_scalars(arg_count, 1, 1), // (number, [significance]) + Function::Mod => args_signature_scalars(arg_count, 2, 0), // (number, divisor) + Function::Quotient => args_signature_scalars(arg_count, 2, 0), // (number, denominator) + Function::Mround => args_signature_scalars(arg_count, 2, 0), // (number, multiple) + Function::Trunc => args_signature_scalars(arg_count, 1, 1), // (num, [num_digits]) } } @@ -1084,5 +1098,19 @@ fn static_analysis_on_function(kind: &Function, args: &[Node]) -> StaticResult { Function::Sign => scalar_arguments(args), Function::Radians => scalar_arguments(args), Function::Degrees => scalar_arguments(args), + Function::Int => scalar_arguments(args), + Function::Even => scalar_arguments(args), + Function::Odd => scalar_arguments(args), + Function::Ceiling => scalar_arguments(args), + Function::CeilingMath => scalar_arguments(args), + Function::CeilingPrecise => scalar_arguments(args), + Function::Floor => scalar_arguments(args), + Function::FloorMath => scalar_arguments(args), + Function::FloorPrecise => scalar_arguments(args), + Function::IsoCeiling => scalar_arguments(args), + Function::Mod => scalar_arguments(args), + Function::Quotient => scalar_arguments(args), + Function::Mround => scalar_arguments(args), + Function::Trunc => scalar_arguments(args), } } diff --git a/base/src/functions/mathematical.rs b/base/src/functions/mathematical.rs index 6fee9c1..af1b066 100644 --- a/base/src/functions/mathematical.rs +++ b/base/src/functions/mathematical.rs @@ -381,6 +381,317 @@ impl Model { } } + // (number, divisor) + pub(crate) fn fn_mod(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() != 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let divisor = match self.get_number(&args[1], cell) { + Ok(f) => f, + Err(s) => return s, + }; + if divisor == 0.0 { + return CalcResult::Error { + error: Error::DIV, + origin: cell, + message: "Divide by 0".to_string(), + }; + } + let result = value - divisor * (value / divisor).floor(); + CalcResult::Number(result) + } + + pub(crate) fn fn_quotient(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() != 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let divisor = match self.get_number(&args[1], cell) { + Ok(f) => f, + Err(s) => return s, + }; + if divisor == 0.0 { + return CalcResult::Error { + error: Error::DIV, + origin: cell, + message: "Divide by 0".to_string(), + }; + } + + let result = value / divisor; + CalcResult::Number(result.signum() * result.abs().floor()) + } + + pub(crate) fn fn_floor(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() != 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let significance = match self.get_number(&args[1], cell) { + Ok(f) => f, + Err(s) => return s, + }; + if significance == 0.0 { + if value == 0.0 { + return CalcResult::Number(0.0); + } + return CalcResult::Error { + error: Error::DIV, + origin: cell, + message: "Divide by 0".to_string(), + }; + } + if significance < 0.0 && value > 0.0 { + return CalcResult::Error { + error: Error::NUM, + origin: cell, + message: "Significance must be positive when value is positive".to_string(), + }; + } + + let result = f64::floor(value / significance) * significance; + CalcResult::Number(result) + } + + pub(crate) fn fn_ceiling(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() != 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let significance = match self.get_number(&args[1], cell) { + Ok(f) => f, + Err(s) => return s, + }; + if significance == 0.0 { + // This behaviour is different from FLOOR where division by zero returns an error + return CalcResult::Number(0.0); + } + if significance < 0.0 && value > 0.0 { + return CalcResult::Error { + error: Error::NUM, + origin: cell, + message: "Significance must be positive when value is positive".to_string(), + }; + } + + let result = f64::ceil(value / significance) * significance; + CalcResult::Number(result) + } + + pub(crate) fn fn_ceiling_math( + &mut self, + args: &[Node], + cell: CellReferenceIndex, + ) -> CalcResult { + let arg_count = args.len(); + if arg_count > 3 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let significance = if arg_count > 1 { + match self.get_number(&args[1], cell) { + Ok(f) => f.abs(), + Err(s) => return s, + } + } else { + 1.0 + }; + let mode = if arg_count > 2 { + match self.get_number(&args[2], cell) { + Ok(f) => f, + Err(s) => return s, + } + } else { + 0.0 + }; + if significance == 0.0 { + return CalcResult::Number(0.0); + } + if value < 0.0 && mode != 0.0 { + let result = f64::floor(value / significance) * significance; + CalcResult::Number(result) + } else { + let result = f64::ceil(value / significance) * significance; + CalcResult::Number(result) + } + } + + pub(crate) fn fn_ceiling_precise( + &mut self, + args: &[Node], + cell: CellReferenceIndex, + ) -> CalcResult { + let arg_count = args.len(); + if arg_count > 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let significance = if arg_count > 1 { + match self.get_number(&args[1], cell) { + Ok(f) => f.abs(), + Err(s) => return s, + } + } else { + 1.0 + }; + if significance == 0.0 { + return CalcResult::Number(0.0); + } + + let result = f64::ceil(value / significance) * significance; + CalcResult::Number(result) + } + + pub(crate) fn fn_iso_ceiling(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + // ISO.CEILING is equivalent to CEILING.PRECISE + self.fn_ceiling_precise(args, cell) + } + + pub(crate) fn fn_floor_math(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + let arg_count = args.len(); + if arg_count > 3 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let significance = if arg_count > 1 { + match self.get_number(&args[1], cell) { + Ok(f) => f, + Err(s) => return s, + } + } else { + 1.0 + }; + let mode = if arg_count > 2 { + match self.get_number(&args[2], cell) { + Ok(f) => f, + Err(s) => return s, + } + } else { + 0.0 + }; + if significance == 0.0 { + return CalcResult::Number(0.0); + } + let significance = significance.abs(); + if value < 0.0 && mode != 0.0 { + let result = f64::ceil(value / significance) * significance; + CalcResult::Number(result) + } else { + let result = f64::floor(value / significance) * significance; + CalcResult::Number(result) + } + } + + pub(crate) fn fn_floor_precise( + &mut self, + args: &[Node], + cell: CellReferenceIndex, + ) -> CalcResult { + let arg_count = args.len(); + if arg_count > 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let significance = if arg_count > 1 { + match self.get_number(&args[1], cell) { + Ok(f) => f.abs(), + Err(s) => return s, + } + } else { + 1.0 + }; + if significance == 0.0 { + return CalcResult::Number(0.0); + } + + let result = f64::floor(value / significance) * significance; + CalcResult::Number(result) + } + + pub(crate) fn fn_mround(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + // MROUND(number, multiple) + if args.len() != 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let multiple = match self.get_number(&args[1], cell) { + Ok(f) => f, + Err(s) => return s, + }; + if multiple == 0.0 { + return CalcResult::Number(0.0); + } + if (value > 0.0 && multiple < 0.0) || (value < 0.0 && multiple > 0.0) { + return CalcResult::Error { + error: Error::NUM, + origin: cell, + message: "number and multiple must have the same sign".to_string(), + }; + } + let result = (value / multiple).round() * multiple; + CalcResult::Number(result) + } + + pub(crate) fn fn_trunc(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { + if args.len() > 2 { + return CalcResult::new_args_number_error(cell); + } + let value = match self.get_number(&args[0], cell) { + Ok(f) => f, + Err(s) => return s, + }; + let num_digits = if args.len() == 2 { + match self.get_number(&args[1], cell) { + Ok(f) => { + if f > 0.0 { + f.floor() + } else { + f.ceil() + } + } + Err(s) => return s, + } + } else { + 0.0 + }; + if !(-15.0..=15.0).contains(&num_digits) { + return CalcResult::Number(value); + } + CalcResult::Number(if value >= 0.0 { + f64::floor(value * 10f64.powf(num_digits)) / 10f64.powf(num_digits) + } else { + f64::ceil(value * 10f64.powf(num_digits)) / 10f64.powf(num_digits) + }) + } + single_number_fn!(fn_log10, |f| if f <= 0.0 { Err(Error::NUM) } else { @@ -487,6 +798,14 @@ impl Model { single_number_fn!(fn_sign, |f| Ok(f64::signum(f))); single_number_fn!(fn_degrees, |f| Ok(f * (180.0 / PI))); single_number_fn!(fn_radians, |f| Ok(f * (PI / 180.0))); + single_number_fn!(fn_odd, |f| { + let sign = f64::signum(f); + Ok(sign * (f64::ceil((f64::abs(f) - 1.0) / 2.0) * 2.0 + 1.0)) + }); + single_number_fn!(fn_even, |f| Ok(f64::signum(f) + * f64::ceil(f64::abs(f) / 2.0) + * 2.0)); + single_number_fn!(fn_int, |f| Ok(f64::floor(f))); pub(crate) fn fn_pi(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult { if !args.is_empty() { diff --git a/base/src/functions/mod.rs b/base/src/functions/mod.rs index 79e3432..f65dadc 100644 --- a/base/src/functions/mod.rs +++ b/base/src/functions/mod.rs @@ -93,6 +93,21 @@ pub enum Function { Radians, Degrees, + Int, + Even, + Odd, + Ceiling, + CeilingMath, + CeilingPrecise, + Floor, + FloorMath, + FloorPrecise, + IsoCeiling, + Mod, + Quotient, + Mround, + Trunc, + // Information ErrorType, Formulatext, @@ -286,7 +301,7 @@ pub enum Function { } impl Function { - pub fn into_iter() -> IntoIter { + pub fn into_iter() -> IntoIter { [ Function::And, Function::False, @@ -332,6 +347,20 @@ impl Function { Function::Fact, Function::Factdouble, Function::Sign, + Function::Int, + Function::Even, + Function::Odd, + Function::Ceiling, + Function::CeilingMath, + Function::CeilingPrecise, + Function::Floor, + Function::FloorMath, + Function::FloorPrecise, + Function::IsoCeiling, + Function::Mod, + Function::Quotient, + Function::Mround, + Function::Trunc, Function::Max, Function::Min, Function::Product, @@ -559,6 +588,14 @@ impl Function { Function::Sheet => "_xlfn.SHEET".to_string(), Function::Formulatext => "_xlfn.FORMULATEXT".to_string(), Function::Isoweeknum => "_xlfn.ISOWEEKNUM".to_string(), + + Function::Ceiling => "_xlfn.CEILING".to_string(), + Function::CeilingMath => "_xlfn.CEILING.MATH".to_string(), + Function::CeilingPrecise => "_xlfn.CEILING.PRECISE".to_string(), + Function::FloorMath => "_xlfn.FLOOR.MATH".to_string(), + Function::FloorPrecise => "_xlfn.FLOOR.PRECISE".to_string(), + Function::IsoCeiling => "_xlfn.ISO.CEILING".to_string(), + _ => self.to_string(), } } @@ -615,6 +652,21 @@ impl Function { "RADIANS" => Some(Function::Radians), "DEGREES" => Some(Function::Degrees), + "INT" => Some(Function::Int), + "EVEN" => Some(Function::Even), + "ODD" => Some(Function::Odd), + "CEILING" | "_XLFN.CEILING" => Some(Function::Ceiling), + "CEILING.MATH" | "_XLFN.CEILING.MATH" => Some(Function::CeilingMath), + "CEILING.PRECISE" | "_XLFN.CEILING.PRECISE" => Some(Function::CeilingPrecise), + "FLOOR" => Some(Function::Floor), + "FLOOR.MATH" | "_XLFN.FLOOR.MATH" => Some(Function::FloorMath), + "FLOOR.PRECISE" | "_XLFN.FLOOR.PRECISE" => Some(Function::FloorPrecise), + "ISO.CEILING" | "_XLFN.ISO.CEILING" => Some(Function::IsoCeiling), + "MOD" => Some(Function::Mod), + "QUOTIENT" => Some(Function::Quotient), + "MROUND" => Some(Function::Mround), + "TRUNC" => Some(Function::Trunc), + "PI" => Some(Function::Pi), "ABS" => Some(Function::Abs), "SQRT" => Some(Function::Sqrt), @@ -824,6 +876,7 @@ impl Function { "GESTEP" => Some(Function::Gestep), "SUBTOTAL" => Some(Function::Subtotal), + _ => None, } } @@ -1061,6 +1114,20 @@ impl fmt::Display for Function { Function::Sign => write!(f, "SIGN"), Function::Radians => write!(f, "RADIANS"), Function::Degrees => write!(f, "DEGREES"), + Function::Int => write!(f, "INT"), + Function::Even => write!(f, "EVEN"), + Function::Odd => write!(f, "ODD"), + Function::Ceiling => write!(f, "CEILING"), + Function::CeilingMath => write!(f, "CEILING.MATH"), + Function::CeilingPrecise => write!(f, "CEILING.PRECISE"), + Function::Floor => write!(f, "FLOOR"), + Function::FloorMath => write!(f, "FLOOR.MATH"), + Function::FloorPrecise => write!(f, "FLOOR.PRECISE"), + Function::IsoCeiling => write!(f, "ISO.CEILING"), + Function::Mod => write!(f, "MOD"), + Function::Quotient => write!(f, "QUOTIENT"), + Function::Mround => write!(f, "MROUND"), + Function::Trunc => write!(f, "TRUNC"), } } } @@ -1318,6 +1385,20 @@ impl Model { Function::Sign => self.fn_sign(args, cell), Function::Radians => self.fn_radians(args, cell), Function::Degrees => self.fn_degrees(args, cell), + Function::Int => self.fn_int(args, cell), + Function::Even => self.fn_even(args, cell), + Function::Odd => self.fn_odd(args, cell), + Function::Ceiling => self.fn_ceiling(args, cell), + Function::CeilingMath => self.fn_ceiling_math(args, cell), + Function::CeilingPrecise => self.fn_ceiling_precise(args, cell), + Function::Floor => self.fn_floor(args, cell), + Function::FloorMath => self.fn_floor_math(args, cell), + Function::FloorPrecise => self.fn_floor_precise(args, cell), + Function::IsoCeiling => self.fn_iso_ceiling(args, cell), + Function::Mod => self.fn_mod(args, cell), + Function::Quotient => self.fn_quotient(args, cell), + Function::Mround => self.fn_mround(args, cell), + Function::Trunc => self.fn_trunc(args, cell), } } } diff --git a/xlsx/tests/calc_tests/RADIANS_DEGREES.xlsx b/xlsx/tests/calc_tests/RADIANS_DEGREES.xlsx deleted file mode 100644 index 6c8ac842fc72094d423c0e10f01f120bf3d36057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9316 zcmeHtg;!K-_y5o>ARP)Q-6h>fHxdE@(lvBAT;Q#;}Bme*p zfC{fCX>aFZX6It4;pt%Jtk3FU3#80Pgs0B~z{8&Z-|=5O0~N_i%AM>uq35y-R7Zp~ zb~=eyLhL4?O+`>DSO}{#$HcxhJ)~8gjv_&scQ+?ZPuAEXfVc^{1}d5Qd?djJ zSFEjD>|6|r47SNVqzX-#$ncBEk>uNXd?B=GvCanbue&=0fa>2!3eseMdIGzn2;(3I zjHHH6W%)2Xv`8F^27x3)OO@((5N6#AE+N>3ax z>YpUh{v_{m0wYKi3IKo&n;8!vo4dV}jj_GG&Ce`WpRa~8fs`pA!7)Qa^X|tmHT52+k{WOFY!=jGznN%xuDgY~!lH_lsvPbK z9kI^G0aMnpVz?_2r9FU7jJf78y3Qe-*D6*E-`&*)kY;L4Z6Fj0pvfiXT={*}F#|ZP zFrC$xp`Dj5r^$(x@8y)C>zK;xJnX8&$Jzsa!KwBROQIyUBfdVp&x5(%te>e3PVM7s z(k)(RHQq5mY!IYBR{-Dn3%DIZHwohV>LRd8bTs-$S_)&|tfbk$Fz`-xnmg>~-< z1@3&(WZ;Yvdx>RZ;`@-=nu$>*qAG+fE6BdODY7N{`Gx>*aKs!)xEx6$; zr_SV2`+rbpG_7yuAJ?bTUn~~6vS`g{S8%5=#%tC{(>0F@QRKbA*@%K-)7MSb#ir&1 zD(8#su=ydaZeT6S3eDM#V_hbUrQSoD*GqL42LQ)!^T^}~&kqg+oMfowyu0>gCYu=c zz1@&3K-5#q4brc zO@PQ~B(ICQ2e95JZ~f!?L@eCO)V|hK>i%>zGW>DRE-mPwN@86y#@QI&sbz#y%XDUd zQ_p6WZWb#V$?*H2bWjA$RCO1uQd5jQh|e2e6VN#yN`;*LF+DdOsVtG+u$*< zBd4!wn4|fa`diyfzW|41K1E{`J>PFo8+C#HPw{qj9I~I!A4j&%`@2_OP*adv5SYrL z2UWP4nb;sfy9bA!MtrhV0A|x5At22{X0%(itrOOZUuTF!lo$uYcP`i$Vt!Q(r*agY z<15XA#+z*0%oT_jD>)?Ux$dKWi*XVY3{%`Gf=GnTM{LCAS9 z+Jp2w5KOCephuU0`_1gfP{tYgh(ywlmjj1Gsl;{9NWfX5$dX-ny`==-_;f;=4e_K+ z%5yP!+=BQ)sjN;-*7TTOjLWmVUqSrOMu%-WJkcEi9nEeRzA3-z#fEf0~ zpF!5y(#*`oneEqw<7c$ZN>Z|4W5)@DGM$RP1P7Z?GRL4!MQMWCG#B^x=lJl9SK}t# z0?Ky$mm?WeBQdO#qv_5rJcZ9Z{F-<(fE_3sK)Fly0>lcJl)CSUx1L~%FZ5_?v+|Y} z@7`DAY%Q*B&ig>FX}JLjlpSG-JRFTkCgMD=pA)wbGRIC1li?oDRO?s@M=&aJX2jG1 z2clI|AESo0hpq1D%3W-mT72q3=n5vpouMF|3VS-#XX7A!p)~X0Jr~OpE&1|`jJ#xG z9ifWKW8*>&sBkW-+}Y!0T)*`K#hrFlPI)h)SC7JF&BLD=7Wog_rN`5ao84*~U4(ef zmfZqIO2%eVyN>Z}T*6}7Q8RO1-?&}oztEIhu8Xq>V1X*R@$}ZZx4hLxSNSj!`fPDm;+D&JHI{^KJ+^)E&8=OmGBcviQ&e9drq(i2&7;`iY0PY~TXEU! zYhsGwBOlIe-w}oc{fOb~AH;G;Xa^KOSNPX5yJ!sB1+(K^r}Pz{;2cyfQoH)0j}W**OcAd$zn;FRV==Vh(qe}_BbhTL>i@>8Gk_&yxzk;;9`xGN z?W7|ye+J8D>n`<}xotzoYj>us_ZjiD`e!mR4rJZe7`6Np-`VJmKt)xNuBvvodb!r`c5G4{}AE8Zd(@Y}~NK+Y9 zu0W9^yJPy^;BJ5x8I($z;*8wD?bL*h0o(je!$mhK5tq?R64dK%7dRtI>PerUz3OSh zV-)F7Sz>e1_Q#))P)mpOzlK*QqsewuMvIk4){K3;KL-~TA{v`s6_jp36Rg@H0Vc4G z<4;}tj{fnqzkX6YxCyXdgak)ho26*O0-26f8>05d**i}BTp29U)NokrWNc3aNT)}c z{7(MtQfcI(xbU%OZA+tmOtXz4XEnEadAy2KBOQ$d~CVhG=CYaHK-$_^-WoT; zqT+pgYOW#t`qup1RvLuJjL71BQR?i^aQ{!ni!To<_Q6Uj+$TQ;f?texu{5(aWBYaf zMfP3Yp*XT8f_9>Dz-UZ*s57=&zCH=SqJWHp0<1Nxo^B$9GPM-)^ULZi;U197!zC@3`H_( zf6;V6YI-pA$cK9e^f@7PChu+Hi4V~t5HvqT-WJMCEbQ`GaL9a=bn^fnX{;uOb*ek4 z(8;iZW{YIq1VB$ImH0mAm4!#3IZk(*BIhbrWFNim4}&mu+B|;LU`N&PyB(r!CR<0B z05v(?LwH)_V!6Y^uIMC1w;PnaDK>F~o0Ew_B2lo<;dz>&&*4$G`x35B&v;4Qw+Cu1 z%!4=AP1U!@Y0KVsx2x5n{x>qb2FZuj?Khp@{jZPHCOb8l6c2Y)mfLR+e`x#P9vLqC z?2Rt1Tk3|X$OeVF2eGyFG6%w0znHx~OkP$re)!Z_E|1tnP$SM12&Xa~(c<6>%sgNS zXI_V2G8C@=kkjo$6IlQWcQl5JBPsCh$wu}lxnk7usFP3IAHFP$_KqG6Er-I%v!KLj zk-XPlQ|FJUl{!w&*T|<)u05ILa*M4sammFso;!W}g%1x%)ix3_BhzJ-h?cG!sDb(@ z5%Idt4Hr>cuaVzx=aj@X#w&siNUezR{LweMx4PyZqu%_T8kJfd>#YgK?k4*b$ z^~8iAs<3gGEm_8fI`j*zu`eY~P&|2U$e2#OBX~JzcP><1yEDbT38+Y@pkUmQHcn( zwN5dPPRni2aV-FqM^cNwtLl?i!0t=Ua|S|H z+R_$tUa7~pMxnbT26e(du`@FdM@S3N)_!p32Fz5BW;?x&et;ggwfhlMh)VTV{3Bn? zk!(P$x+d^t199bL|kZJ zik*0ulRs7dv?fcV(*Vn^oZbgG^rz)Za{)ms#sOe)>NV&c@K#V%L9uM4R>w|Bl)_4cgGgxpO?L$>1U zUPwRak(AUr#XMgCPq$)nO`+hCAXP8g8GH(~w$rC8Aajv0={CATUfQM~0Xmpz)W_iYkyhI5MCn|Y!wfZ?SGxwDBO^|v* z;QRB1EyWJaz8aOwle*NW@G|<5?PTn!+k@;->E|-z>0Ql}N(5yacw+1+-<9=Zcjm9Z z9@E<4t@_G=q&n|~wA3o>p$EN+>0=Li#9uN78Bpn&B7-tQd{kAST(m4Q0Q}k3oPGK# z@9<)23yD1zA=`veWey{=q*3rVQclFGEnnR55%>oi(t?ujBEu`|u@^WY-&{U9wKIMDYXE)BVt`hYt+R6EjKfSW9WvB_1S1 z#B{q(bKJ^BbS)H6Z(mto&pYImDnAK(g;KO%o${)LcA+|k++*>K(}4LvG4;m4S}m2Q zDSl0<&Ou~q4f;SU5s0)e@&=N&lw5UTf=D%OIhE`VdH(58eCUIh@`?~Jvp?#hwUKjU zZdu?P;}J)`PV^B?Vb&1VD>iyPfh#+k;BkEsbM~z&v|*{+-ggNR!p{j3)`#PMD0r9DfF&SqS`J@1rjY7v%6@gJ^)>HcIA)~7P zws?ywQv<8cl%}=!-~AtRdyP>7F&V{MIm(`&(w8)lwRsiJSWem$NV5>1bwb2cdgLmN zz&^yCRyg{QWzns(Y==rI}^1$ffwFQFB+c|*`bUP0nMlIcYMtq?X!374sIL~DEhKNCMCNTN9trl&|C0{~cmBz|WXPoSCe&-(toh8|2! z!S~B;xO;t>O={Vfh+2|SB%9J`tuAO){orj^23wySXPwoZZ?D+HeC7E`@XC7Up*z@F z$zGRXG>2pmG~nPuVBDoq%2dTea(na&kt@2Qpe$d4DRmX0{({#3juo^|IXjWc5e|@; z!?e$~Aq<&y8l(nkw-}+{PJWf$S+VBn;t3lYxROzi=ff<1u3qI3R};T+7a(g5-pk0F zta}$*-Mq3tYGgz`*xe~@B{>6M(l{29S`t%4D_zMiu-(9REo(q(>$+D3NZV@Jr16$> zSKbUswV)RBd!(Km&kl}gdsh8C1E=$BAq^X1Rhd#>GAX!`_cr*6${uz@F+4Xet*5T_ zJ1i$v8d>#XHI2HZwMNIU`7+kgxBIp>jLm!}cgEFQWrD;C51P;9*KQt!hswN)z3&0@#29ZP{$9K`fo|wDo^fK9^ib@(o80Y^o0pcNWIpVuDNGT4QdJsVh zp1YdZhDpYIb}@pJ4*PewmThLlO)r?wwVa{Bp#6f-vmm@Z%#nkU z9~tO$M5amprsq1qxJe|$9J58Iah(~H~dE9Rq@Kd0OB()ot=gd0Gni_G8h*4>lK5%JrXxp{0QDx4tUZ$16Xzz<}-R@$4L#k(t z5hL3)mQjve0P)<3@7YMb+A{09t!n;0HnTt}4?N`@)DpN7%PZrKfB7V(@9zG7x!=2K&I#}q{er}gv6tmOkNZ8JX6*R zL0ywW?G(1n%IYUInU9y(5iYw@WK8Tf&g7vb zn5?PhlOUWp9+gav<=oB}HK*QbynX&I6O&tZw?;-mEwx~Mfz0m;kP?*3ven#>f*>UUbt%*0w*Rm23h*`o+cVk(`QC;a^xZ`pCEk}yR79{<4 zzLqs}=X>OOrnumv{3i>|>`)Yp47fif!L5U(${|ywjI#Dne z#`&xJ8aX)p&wF7L^XHKj|GU3KfBuX_7B6F5ab4jREnoCv!Q|c(T|xQJlegZOcu0=l z%zuC=+8gJhCE1kYohU0d>c-UpUe@q#AfH81R=f9o-A3zP5+xgmI(EAop`LR1R4D)* zc6eu&xWX=w`W%IkL$fi7juit|l|zPrlr5RiLXtlP;7!Z8SK({s04(k|d0(Z;y;brFeitJUt>F+86Sz7$Ry#jS=Bvl59D(*r?Js`y7JdRl%k)83lr*`JIsp z&L>?LT@&_AtOywXPPC7Qt3iXBh1HaI=0=hZJQ?@Cmq{n$F^xXb9R^I~rL#>U?pt zHFD6Rb+xj@&-nmCo&^N*{`~(Q|ASXxG=4*-n;yCULfSJZzrmO)i=m&sk+1Cw;uWyD zM?Y$F{SgJE&4t=eBm+`Y{OD8`4UhJVhKe;cKx3&>HBe+c3&)8uPJ&OgvXXI1O~a6) z`v4+zH+gp1*R(RAC0kp!smxMrU4c1p2j#%ca}H580UG)mSm-h2`31tsvP^rjT`8%r z51-RDXv?5<1u!vTSPyym2=+e{M@qW4l3ry+ljPoY_fwg4b7+Yp1jo^ZJ?_U?V>5ma zv#2b^)(9=DLd z7d+r6rv?@%t6?{;D;iB`8OsbESpS@d&i$OOo2sao{uvPjk8+WuZXvpU^H3$wI2NTy z$K7T+VhTS}@S(Sgtpy|CA%DGliW4c~glVhsCs_oa7KCdnE`T{_^sAqbUOuqw%a!Pq z;CTLJmbPEvtEatB#WDnY-lY8(h1}0}keq8}ypeCoU1aa{_Vxw}B=;{&Tc<=%bo+is z>YXP)y)&(jy^*B@9qq6Ff0^}vFo*urPcMy;mhGX34!jV14jO!zTZ@7hkaXb}Ya#gJ z?IXSlR~Md3jJ4K5h7JD((+^Y>(B}O-yt2j>emqEUzs+3w4H21>sNSV4F!9mO34)T; zK0(B;bgLJ^dG2oRK3P=4joi5{lCq?+C|h!9gGglNN~j8cf>s3+3Mn5u5S2Umt9rk* z+PeOaa^N`u#j~=&$_BQq2AGjP(3AsmqWha z@QT*o_1C{MiNjp3jS46bkm9?dgL_{YS4%n<8+!|V8ykyXTCG$`!={8C-do4)4fL85 z3<=*S1vdc5B-;L{pmxnGRFghj$(m6n_W1Dmfr*qrd}WUEn3mA_H2LTASYOXwgO(b3 zMO;H^xd^1rkyy5px=E=!ZuS$g0#077?-vY;B}?Xf_1(Dhte*I`3kxq3rriD%Ft`4D7haD@$EBv@yr2Ec83)6sLl!&9t?)-dUy6H;(xtaUZ5~1|9RfpJ)U3T2kaO@6Q+AQ~uwjfW; zrirj{91ZOxkcj0_MoMF9Y&eh!l7#i{O3p=E2@WE`{BwEs=lxDOGGkr;d3tDpjTj}; zr>X~lBS|CV;`O5lomx2*8Wh>lCr{i2<_Gal582K(kCm*cGHtkH256 z6qtiebz*MoBC1b?lsfXh>C4*Ij;A12ZC%=dOs_4+8aOU;Tkk)G3re?Hl&>>J+3~8r zrEcT6>P&u$&kg#7LUyCZ*dphGNm?>+sIYf63fG@_5}7!1wITjP1>k=l3A{$88KISI z?v=dy{H}`rod+$S)TA)qxpV&m5D+F1B=9>A{!Lf?GbjE-Zvnp>neWg3&puk?Cd~cm z;rlNF+Wkh`MApunDX<r zAB80Arm&~kze3hA3zt#BUK}L0a0~7F(+U|d+aE@6CT*-^YgZwR>kulrAiJSRW5+qH z5g8Dp)cfksWZ%b6FDkR+Er&V@XbS~UOUB^T09f!d%|r@){kT!q-&S4Le*&x&6Y6?R zhW|zNx)X3hUFVL6$c>1~5SUi}{fG!Vy?E^zWFigBOoBP6Lt6O$SwsTKw)OxGzYPV5O*hucm`J^}2~2A$c(GtbU0kH00mAI)Mp zSLB(E;Nq#vFyNga{++UDM)B*a-=#Yh6c7;l`xAec?hd9#Mve}2zXyh2Vm>WaCvuq{ zx^si5ZPwf~k+~S;sVuuD-7H zj0&&Wb6V^(rOgl~`5Sj@V%cYqRZ}7Zi68bxzhAqZOpb(SH%I=IqIAB!l{rk!=*hcE z6;q~)1Wsiqt!Cfz)OhuCg;&rLYq;A87&7VZ(T0O?6_#F4RM6H`jis`Dlv#WR!Kxog zY%8aFW%KY7$-ChQSo@wCSz`LaJ~1!^~Xo|6_IAz zzDmvP>?Y#mImaN=ol-7RuSq9MGj$$q9^t26z3=iap)T=$z1QC_*YV4U zwI4nFbNpc8E&OHq1_D0_qEg#!lsA7IsRW%BnEd0D7Ub5;K_tS;%11#wC3f)+I4B+az zpU6O3r-LSbwlB7$T;Pp>=v3dXuBVbC533m=YxJ%mz6imi~fI7@-m3 zG`9mX0ucgw4%#NZZ}cU`lBCSHL=rDU?AS0*`)!yMyepf+#iWN4X9k1T{n+?lt?{kSKY&WY_5&RRG8{0`kcRL%JXeSS0CoGEfl`;7Sp= z=S#q${=5;%<-W<R7qZc z>dYyS_$dC9gyd%vy|#$CzJxhKut{lNR6?c>$j;%)(qZBOnh}~wUO~d*FVX++e7^0k zHtGDXJ^bMROFn1(&F3?cHo5fhK$}kzFK`JLy#Z7=wT>Oy%4#bgV{D&FKbnp^Nao=X>n(x{sN(!&f zk!Ux8PdK>W1;Cd<66Lk~7)ZbUT;v0AV4o#2U_RRA-dQKPUfBuAs={{$j`Pj(!pePx z2h;vJeYz6-m<=(c^!&N~@NTiI0-R-Xy3MxZ_6p-iy~Atc==1e2GyCt95tb-zv-0kL zyh&`%IA22S^~!(@_?+D~uQ|gte^|@MiOG6;$|e6PNvyTO8tV2UhOARHw{zz1l|eTl zskO%YYIR-+nKQO?vG?-z?eo68R@<`fx2XdP_sut63&s3Qr}*~AI_u^HI17qnm>dyA zE9jvv&GNb_jhE|_y@7^)&x+~PTj|8x8_$g0Fo7DIgYAa1`9)=QthOnc4cdp33sZ-V zb=!xZRRN&G&m6*PyHoZs(({Mc1`q)=K1HP0`~niae5{{|Tq=v#_E^c2 zl0G5qQIc~a7#+yPY=V}BR|Ft9aF5EgOW&g}p;&!{V|pD-5Bq&JQBMM)fH;Z0GzP|k z+D?^}VW~$d&Lq)`Zu%4_T)bPm=2MAV?=GFI<-(-`PB0mDT(~*Cux&u!>Ye~UDJPb5 z?c)-4?PrE1fXWpfJWgF#<=Gg!WVfUMmAO*VlR8eqTB5K)3=BpZ5s@NB5@T7Z386>E zW06yCMUr7I_`xg#ao4zpy4pmqr`vGeBJLn+nBI4sO9%Dqt)w~Yp^!RMh^21~mdVcI zlaw?xrDs$eODfi_$V?O2CgE%xfjDxD2ep-$rb96-_)D=}$@X0tRO*vH_t{|d8U+~H zeu#Lkyu_P#g%G&I-eQwtMjhZLi^AOz)g?}X zzxLuyUWU+|A7vN91%XfRLrmTwF3P}q%S|rEC$I4$Selz8TuhZg<8nENi{cr(dtX+I zn6!egn+)(s_+Myze&xUUOUeBA%PKfnvwIQ*AfPSn|58>l{gzdV8aAo)$ljT?Z$8iC zeXAh?-}9tvB|MUxhca*sd{M%Z&zOq~ULSDqiQ@^4wZzRQOrzK5A z8tiO1f|*2-kJ#H;vfSLP6o$+#Hd}t-Rz(GAGucTm|6n^4hC{UM#p2CI0mAh11>op|;$Wus@KpM1facRn$@ zlETO|d*>-^M#aj+>L|(WsN>q37BjmeipSO(xOUNVq+0h>@<>M%7#{Jr2}3PS^XdcP zh}ZIj5yNwCo+a;?Jm<#2{d>Z31&`Bf7ekj7OJg@f4zNpE710mQ57Ixh z=@p=7>%Bazp%M{u%#=TTB7PXBjKeAz3w7yQO^6U>M>Y`2KqArhc|$@N7a>PJ5J~^w zp*CscSO^LjEuj*@3_kx%*RZknH_P|8Oik0&ido@cXI~xk) zCGH7*c89!2JOvJF6GYrSKcEwK9?`E#8DHn3W;Lu5t}012jK1z^*x&)Ywm;s!%6Tdd!yw}-X9aD-Dm$Qxm(D9e*T zYvL$%58~uVpf?+QfihSSil=wA`T~{ff~hPsLF9PWIE7>=0d?J;I~*yB-dI?EJF;VO zca``s)4{C?AV@Om^yI3an-(bpIlg#%T1ea&m}qI{iFml+ZC`|$?*SjVJ2|g=w9Ou> zY3*@UAKzzd5Nnb9v<|?ye|3Aj9}Bwi_{_p!)v41vhu3R_ViCN#>U4Z*G z>LAnfP?(F;Cpxr~dwT`U?Qty8@niIHrLZFN&F*ghH9Mjb`>JX0Mt*U>iRy;^`}sZnvU_a8#cu{P)jzQN zE9mu^W(6ACF11_Zz9l}wLpc<|5nq162~*qmP;^&}c)dZnqj<%N%HFS$#I*ygBFVEVtJ&7gt@{7GZ3T z4YZ^5R6}UL5xMXNlshbuZQh{==$fs96twHemOu{Tll`{s)|4%LE_%`px^41OU#B7T zx9-C7)lgvcG?G4v2jG?*)gw;b1!O7)AV+W53q9#v1}pyD7Xa0G`pW?*mmfyG;M4tdCdv=nPGkddvx!Gu%!yEyd0 z!Ghk$EibvWAd-)v*2OZY;?`!X((qMJ8O_s~>A2+ckdUD)1rVVu+XSt`qB@hS0$}ue z0V(rl1Ps+sBJ3}MYmkNha-J7N!_tzEL6~U{p|NDVHB$*$KP=|X-$1sp&)PXulX_$NvY)|HJi0|1&+)8Ka8ZBg zKP;niSd?}i)bcTQn0!UPvK5HdOc}XU6MV$tBPwm~-oZJ}OSUYanW+zlzRpGFIx99{ z3K&a6y}2-fM8_{6R6k(Tr;I}R5M~jy?_(3NN1iGHi!Ro=4gs@|2JHUzV2B@*7qNOR zJMcIACZzh$j2mGLbWfPEV?NsUwbK~RB2*E|Jbq^^qEy*k_af_%^K=>%{YK0UWhbUw zBPZZg7>Lr<42}B<0sfOMpb(!v#n$jH!({kx ztTrd}cc$ENg!a4HwUA0jxS=0;$sVRV5S0TW!XHI^2vm5biLuCWWWo*IVDVMTVId7 zxVSi<091mxU$cKpZ@?#`=1|v$oT7@De*j*wh(L8-&sL_nNbFxxw#e$sSXns2oXFr% zC$r>Rz_wDD&76ddlx~TI$UfX$_w8u5->nbG3AToYgAztq$F#j7@0JDEM2fK6>&DxS zi7%ouNu>3>n!p{krPpyUWoK7&|6!-&K);aB_DBh@twAF@n1mhRgiJpqHbsg-p+1zf zI+JZ08-{EZ6P>fxdNMJlz-ZqnE&|&jB(f7XiFewg3?d7SL+W6dB((>%yb+;#jN%)C zWnYz@bcd!GLy^HVleSH1<;M2gq1fOVsy8MbPM6Jo zv#{1+Lb$!`ocev9k2{tj`&XBYyLX_NN{F2zwZ<{Z$Cx1%gC5@#Pb}gPM78)Z%saM> zLfE`-dPSZChg~*}h1>2>i(3xVyk(lMA>q>iu1Ui7>uu#}omiVOuxlnmm*d%J3O7ts z(4~P|f*o*0%1g{yt{oD!UOSJL@pN0js_?U%4}bNWD|Rh%-?hD??8bt?t64F;iwtd6RJUW<*=CgrP)Ub38jQJ;r@*8vZ_FmpeKO$ZkKYT8XjTS*&RbX+g zD%@-)ukbqX>-wA!^oxqC{p!)S#n$~X64S4d5U>eRXBkTS&F;HnB!P6SHm(jNJ$?6O zQ`(VybWU%EwP?+|fu9Q|_?+|QJ6Rx35TQveVCPw!pn2>ot8I(J;&Dt}ov0p-!b@bU@~e zSEI`xzCDh-JiVUMn#Oph<>%RE2ff#m?C|K?Giia-;KjWBG-#OmZs zyB4I{mQhaT+BCpYD|;db*w>W=?3<OBU=1EJ2yvRhpJ%w9wCLqDi?Rf^Pti)zvu|*lfsSn%`-Z2A;|YO;Xc71|Hl9e7 zQ+U?o0izQOv>X}S)uPkrobQAT)SH4q)qah+$bPgT8@#zC7Top9_F`nLHA)Jv>8Y&P z!Qnwe@nHYFVcQkgt;6cTK7Gv5`d;7Sc(pXt#Mn!+*Wu^D2Dsrmj1qhfr&+X+weo7u zP|3BjR5U7%vO{BNt?5hW7Ugu#9c@{xm)~bs{~xqwOs#Y2@7yW(?OqmK8>PMLL}aO{ z7MVvyk3;SIvO}cI`(>^vte-HTr|e$)B>k4$S@=ssr?Ma%!rhrtOVR*j1IMUxi2Jn z0v_P%3lX1R6ML+dcWH4Em*pCXBpAQH_G|Wd?DT4OfgWi@Ot>cBA5`xHzC$BJSem0CuG12owlUsKVguW2=g$48rs|~Wm`gd z8OhzQeu(;^YTfZwn;0gBZ+y*Da)-STn3PK3ZP1@L0kU%{K|3yoDZI27xgao|nQUP!mh+N9Y097%4D2EJf>(?q#{iTgAZZM{qBDUy_E z&^lD2^y3q`LdGNs8C`^NXWy^}!_6ypgqS((LM!jUg#&x5ER^e%Uk{GB0PeuLqqPYI zKd)VPq7}z$+QU_K&{wjT5EBy_v4b!!9p5@S7|R)*c*W zu%vOE1@j~f>{fDsh+?G2iIA=#7bCj0a0N`_i3jl1X>q?cenENKHmgJo%O@JV2xzNn z-YEK0fE1P_nj^1_F)2i`gelP;IlZeQz?Y4~ivG%StZb!q$m>MbRd6eULfLuKRSSeD zTz&m1EVTyjamBixSm2?@dbcF54B4e4!k1HUC)RG_we3|#lT7g>a%ZiHuX$z-<;e)* ztuh#IU3CuY1m(WVCd698W&upz2CI4b1s->3wjTuqcAn~kt<>t>=;s4v>&gwEO*p#& z{?o!a^$2C_&Xo-4+Vv0g^WcHai+e(>BUd^yhlsd>BOY5{DMd9PzJo8bLv`@HiCw=( zR{jy}`|l5}aE{A(-*rZ^2| zpUSaCYP@wra~wUO}*XvbFqVTf=IxgYgmNpQIfKf3Ok>-hmSBmBD4=N9hGOb!Ny58w3$JPj%0xbbf+oi8mRBooswns(x6f2n zB$hEf@yJyzZe$NFLz)V~xv}J%BtBZV7tnvY@PZ01Y{Xw8JG;i;z zg#U;Ft8`hvM}c4B$6GAYWeuXuus?AhdkXt6{_^UtYz;BWOY;P86Sn zW-jEBGpl*pP9IEaI4|l?b}|8M1JdA2V@DU~4^VIFb4$)IQkytA2hz^nZ#oSlPFKxZ zXcOLLnH5T(HL-pBK5H^}={u-VM-2zal3W*4#~z`KRJ)k=k;A($dV4Wvo_}9ye{7|N zB?d*uK)XMC+L?Jt3@W5|mcX!`A!M^^;vX5_)z!umfUB>kYuR}Ut)vPQK22?gb$ zZ;;g!djB|9m-sN3(Oi`QdApZZuL5#aEulRR5%#D@{N#hPFZv0_eu(%~2r_4KP7sHv zuOha?dbxfjS@I@iKG&li&{l{QO6ody|BOJsBlE2p$r=bt+zkYw2E0y(_dNcV2K$4l zzMal7!}@o9MfXbAQ1`Y?a1phf!;`g-)wu*x{`Oi_h9!j#175ulAU1H{$UIbOR{He6 zH%FLTpV?RoF_&!|np@Cz8+EB^X`6wu@B)5B%q>ws7E0!kG1esmcI%FZjpv0s;e1|X z%qsKGQKnmD6jLM=t2r_!o3BP@*Q<1rMs7K}gp zc@~Gqm7%2#?T70ll{`>I%S|a*xX@83VU1QHE{-iOmdeAip5MhOsm^t0+gqnLP&Nae z;w6-_wQBg5G4<5lSlmL$C|w8D9?aEUs;CPxy z5CRAYf$&$}@9+I{M^hs!Bf8)H@2&Gw^|45-29yr8!#Db*meMKH+qz2Z!x=0Om$u7c zTKha=2|+p&cKqTs6cEq=hhq{xpW4HGJ{#^2{2;`9e%g-%=#^6i03p1gXye8l{R&>6 z+C`Mgq^;-moyZGro_2zRb21gEJ6d`)|9q_uXR=G~wDHBXypi%ZL&ox2FIlm;aReiZ z^G6HnXW8?Ydp4J;uVHq++)=W9z{ihOaZCJll*W@`y*LS5$Qd-~vQhpT?WN-!%^%vJ z$^!W(OG$(C+7oj=%<`yH4?=q&t7vejW@cS|!qm!8+;Cq(w{03~H8bPqXHP5z*uP zZgpn?6yMS)uklj<$P6@QOs~+BUs{98(tk!jkifS;o!_EVVZ$EBw_n}f(==}l+dVj4 z!4Hmi7GbxF0fU9A?FZdn<#z$5*P+;OiD`H_hU3Y6T-O~Pu#lA$bL)w=W?8o~hTRrG zjn3`Z%{gW~iMf9X0yb3{PCM7&(MMif{R)Iszfk<@sy8fF%J~H%YmSaz`{j0K1dX@d z^Xef{$MfpC&t)A!t$(_xdKXr{nfl$YX{dO;N!;*wd)=zw1-yu|X~$hvbiDMO0G@9W zXM4U-NnIVwZgjj}J*fa*uXQ#&&nDM*Ow|Kr#e4%?eCgT-sJ{Z6D=t1?#cfFGBNFM0 zXQ4ZCeu*@+1eTo-ZnpKZOueKCqTT^n*Ws>d%;@tZ3CTSOveO5S#K`sPPX~7`dZbiy zt(HhUAOHD1%p+_vpyUErf(9Z|86!_+TY)3EO86!&=SvQWOx5iylXFCsfnz3u{?c92 zC_9oRLEA*|f@rT<3{4Nj0)2to|yMk?hp6>AWO$!v~C&^U^~RMO}`#9gGVT4Dbs*ANJK!GYpTHI{RCX9=q7jTN9UCr$ov9N$Rfte4r{luKK^X0Bwk$FumG2r+I%L~w=qj+aOYHBrULh<}3Dolo(Gz0VdYv?u zR})xY-@MFfY-l%7nH#{ytoV1_!Jf#$q~&|~+!QVE4#P7IFWM)3<=jaZkny0}?ua() zjCle@+Q{6>sp2=t#fc5)>4CQc}@?9A%>y=1gI@ZLqQF>z?r<^I+)LBE4FQrD2 zI~m6oaf;QlhTGt0e;;xOfa7r1!<)D4IGLmhGRz zx}ZGpl#{(+BBc=pLSAgiI43Xn2r3jY5jdmavWlLRVbC**oot^5%Lv}GVviiZZhxW! zTb1@&qtG;;QY=^;4fGW$d13G@iy5q2<(siD$SQV$a^Uh8Kk#6Rb9w=nC^)Z(*DNAk ztq8|QfK`sM1Uu*Xc96IpSN_A`1HruMT%5~+ zQ0Eo@SfjhlCYNREQ0R}Add9t_jnBK3*9)2X=5;&bmSVJAFVC?rnPvC=?}}H z3MK2h+aIc*_UqKu%2n|=`*O_kQR*z4YmNpq_9RO~m1gyg>>uvZR+fl4A-^0jUcFiX zLe!^{g{2wR$9gEu4$4^T;8YRflr#5nTddHa3Q5+Tjv$&&C+e4O zF^D4x(g@3oIL-MN>$=|~8UFeRys1~cu zJ%7P;)*@Gg2K~P0fKRqxyiBj%6TQa_Uh80k_wYX520v!(>q0t)x!PXvETU%; zHLU1ga*VSM8#v>YkptU`<}4y})^Ao{=GFN!Kz57f5o=_9~J%FnEJy|pA z-Aae~o8otHbh9*a_~kz3DXsjn*S+v60r0oy!_GU@P?l)YGeBU?IeeVD6`?d_-Hunp zO%AN58=^}x+c`b7XOcowvs(mk`FUt%$cG^qBXz^Jj;Q**U$Q03>oHz$8)1!qWzvWT zC{y=%7+(p$zG|7TX;%i}7{CJiS7WSmsL(-H^+kxAPdJVtdluJ5&vwmQhLpkN=HCV7 z;oG6hgyd;%;p!250{}|voD!b}jzZAXVUJ|jV8 zBA<=5$2Zy)U3kywo&&;#K0=TI{iPt=RvZ-=$ zJcjLx5v*v7{n6T^zXgxBJxF*@-5FhopJ*UbrsoI#WTyiP0Tw&g<7fv6S;uUS+%|Od zafG^Y%$0_U;NtI}2yV@Jvx8>vDx4@Z0i(H%*w$kl0 zdUPC(O*ZrH8dU6W{NDbIo(FU-KA#xj1yTb)4b0gLLyT5)voPPfe+JmKDC5=e=}0P1 zi8K!E3_xd|Mwae|hegUiJd3x$684a_M5a7pmpV0|2BIj>qGxR3EsVh3%-wy4HQusE zl^Rz=9F5(h6eCp`nKS2x+qpbGIQ;3_voqD^jBm%RrV1<@h7pP*;mQ7!k!yMNvFgm4 z5_s9*{Kgein^YdXbfSkmN$Q9?NqQnyH(lt;{Ii-i*@e|8m`knb5@=w-g6MAVFq`0JmV1(IW?JNI%2n$=>jP9Hs6D`t;R0#xkqZvtqJ}bjNwR`mh6SO-f47c z$XNm>gFay|g5^ufc4wAKeU4Spai&%HUbazf3}^qBnt=$TFRS8$wH!PHCw;7P5~LUhu(Vxo2mhed;|;zd1ul+sKN zILH(Iz3nq|QN1PXYOlvcjE-ZR77*WVQmBe&3~O26v)^gxDB`3pR0|O>v>sA|jyijW zwj@Qm+3`l7m|PRc#`7V|NtgzCWXEncuaxNCj5!tC`kY50(v_YE^U;Yn$O=^2t)~e| z-y(q@63+ndtNQN(1tZ*pG2(sAQQz+(yytiu+8D^$+t@nL8Q9nx{SqqgB}xCA+Wk(9 z{t8;MJM{3LqT9Se-m+GO+dHMKVgn(Cf&w|gGi?|iE01E9BkPEd7k1lG^<>2BT%0wz zYge?^>njDWe(>QnlHDd@$hz?}{niP)W=<;Fv4lCb>a644F{cDEsgKW=*{yQ4or1Qw zAeh0z_SN#_9mE=q-y9kCm)_l*6>9QRU1-V(tU;GqHzE zi{}iFT(U8sYjY;~KA{rrG0DKG`%m`MVS(?9En%)c)y}Y=S2ZXnr_EkWNp+W>7_WJv z6OBzAWj<|0_I%H;@>2dN);1}T)dhYG#?3WDb*}yTwOccTkMIjn2(6($2*tk2q6_U| zQW8>}JF^f<*ubq@(?wp?YgL!jS`-*W-dvPg28?600z5~J z?7o}#lZBJ$ai|g+iOF7C*>{Oc3x)&0)0phz(--?}9FxcS=)|y!AMuU4zAxoX#Fp<{()F^NfEmUBol~NF_SFL#3CwQS_^A%Bqkbt& zkWMDb9=~+2dRhU<-5kWZ&U1~I);e#nPjAOvplI)dn)T^kfSWinK|GKeJ%|HMWPWd* z!V;dIZIeERni&O5xoyg4VJj@I)mQ)?(6{Dk_k3My9~kCu?4WzejXd#h0$A6Xuh)9K z!mO5Kto=N$DnBGzKJmyG)CUJm3DRX$!9j|=oHK9+mHQcnr{r>C=JbR}I^6dD=$)}? zpauN|uqVYGuc#YQ%CD$xwO!VkdLaJ{Dn=Em3qP{bHXqI{i)5Y017NQeedQRITizPlHKc|nFh zap}CYn3@}oztoUu10D~4n%zB|-(CKw?s%_8P#H6C=U*cN)}T0Cteqf?_6hY$BvIo z^VKr%a)aLPzFmKcgOl?PyvBWxCl94^lGDT)#I}2V=j7n!Jl$;aJAlpLbUpv4Nx%VW zhK8&4R@1*s^e`gy(7p8%zv#9S#xWHax+Q9-$7z?vX}85`kHu-P#c6w}xSweq)w$#^ ztfSDYcbWp{f`y^}zf6p3eV~1SX??(o<%r`$API?r!|)k>2mgO3xri9?gGE9jB#e~N z@*!dFQo`ptM5nw(DF&sW;pEW%K?1X;3D(r-bp2#3PI9^5rR4361catOT z)W$EnBkpLa(Y7Mp7*Hm}Y0+8QqD|MYACj8#+jLAloj7wO5d4Sd`V6KUrE92ZZ9mT zlmMHgyqnNfE>1$vuU~}}i%1&u2eSQCbL^xEU!AO$>(&oOa1*zW!Jsk5WS)UQG|iQ} zkFn*XwtW8FG6!U&IlnkR>yKun8DXfQXyPglB8&SX%ugi~d}rc;&Vj?v^9N>_lG$~v{Cy??Cma9cb;!9? zgzpXCDsKlNAE)y{3j}nUcU!*vxZ%EEv1w#FZ-5FNC}S5CS60jH$nJRgU0L$0+8r2# z=G}n*&woS-VUa@lk63G5o9F^cOr3kN`Un(7$<6e}ez3#rn_S u5S;%6{&)NJPv}2QnZMwvxqpBCe=%(2B*EUP9S8{a{S)=hFu4N1&i)VR(C5(r literal 0 HcmV?d00001