From d4befb18cf5eeb76b27d20df322e6a2fc1815cc4 Mon Sep 17 00:00:00 2001 From: "0x_Dave." Date: Tue, 28 Apr 2026 22:46:14 +0000 Subject: [PATCH 1/5] feat:added more functional logics --- cairo_program/src/integer.cairo | 77 +++++++++++++++++++++++++++++++-- cairo_program/src/lib.cairo | 4 +- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/cairo_program/src/integer.cairo b/cairo_program/src/integer.cairo index 9501eca..66e86e9 100644 --- a/cairo_program/src/integer.cairo +++ b/cairo_program/src/integer.cairo @@ -1,12 +1,44 @@ +use core::integer::u256; +use core::result::Result; + #[executable] fn main() { let result: u8 = add_num(5, 6); - println!("the sum of x & y is: {}", result); + println!("The sum of x & y is: {}", result); assert(result == 11, 'invalid sum logic'); let sub_result: u8 = sub_num(10, 5); - println!("sub result is: {}", sub_result); - assert(sub_result == 5, 'invalid sub logic'); + println!("Sub result is: {}", sub_result); + assert(sub_result == 5, 'invalid sub'); + + let mul_result: u8 = mul_num(5, 2); + println!("Mul result of x & y is {}", mul_result); + assert(mul_result == 10, 'invalid mul'); + + let div_result = div_num(0, 10); + match div_result { + Result::Ok(value) => { + println!("Div result of x & y is {}", value); + assert(value == 1, 'invalid div'); + }, + Result::Err(err) => { + println!("division failed: {}", err); + assert(false, 'unexpected error in div_num'); + }, + } + + let input: felt252 = 200; + let mutated = mutate_byte(input); + match mutated { + Result::Ok(value) => { + println!("Mutated byte: {}", value); + assert(value == 199, 'invalid mutate_byte result'); + }, + Result::Err(err) => { + println!("mutation failed: {}", err); + assert(false, 'unexpected error in mutate_byte'); + }, + } } // addition logic @@ -16,5 +48,42 @@ fn add_num(x: u8, y: u8) -> u8 { // subtraction logic fn sub_num(x: u8, y: u8) -> u8 { - return x - y; + if x > y { + x - y + } else { + 0 + } +} + +// multiplication logic +fn mul_num(x: u8, y: u8) -> u8 { + x * y +} + +// division logic +fn div_num(x:u8, y: u8) -> Result { + if y != 0 { + Result::Ok(x / y) + } else { + Result::Err('not divisible by zero') + } +} +// Convert a felt252 input into a u8, returning an error if the value is too large. +fn parse_u8(input: felt252) -> Result { + let input_u256: u256 = input.into(); + if input_u256 < 256 { + Result::Ok(input.try_into().unwrap()) + } else { + Result::Err('Invalid Integer') + } +} + +// Mutate the parsed byte, preserving failure semantics. +fn mutate_byte(input: felt252) -> Result { + let input_to_u8 = match parse_u8(input) { + Result::Ok(num) => num, + Result::Err(err) => { return Result::Err(err); }, + }; + let res = input_to_u8 - 1; + Result::Ok(res) } diff --git a/cairo_program/src/lib.cairo b/cairo_program/src/lib.cairo index acc7644..9ed6eac 100644 --- a/cairo_program/src/lib.cairo +++ b/cairo_program/src/lib.cairo @@ -1,5 +1,5 @@ // mod hello_world; // mod short_string; -// mod integer; + mod integer; // mod bool; -mod bytearray; \ No newline at end of file +// mod bytearray; \ No newline at end of file From e919c742a6c6f71ca571c02c70408b4cd53be65e Mon Sep 17 00:00:00 2001 From: Chibey-max Date: Wed, 29 Apr 2026 08:34:51 +0100 Subject: [PATCH 2/5] feat:updated functions on integer --- cairo_program/src/integer.cairo | 65 +++++++++------------------------ 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/cairo_program/src/integer.cairo b/cairo_program/src/integer.cairo index 66e86e9..abf3435 100644 --- a/cairo_program/src/integer.cairo +++ b/cairo_program/src/integer.cairo @@ -1,4 +1,3 @@ -use core::integer::u256; use core::result::Result; #[executable] @@ -7,15 +6,23 @@ fn main() { println!("The sum of x & y is: {}", result); assert(result == 11, 'invalid sum logic'); - let sub_result: u8 = sub_num(10, 5); - println!("Sub result is: {}", sub_result); - assert(sub_result == 5, 'invalid sub'); + let sub_result = sub_num(10, 5); + match sub_result { + Result::Ok(value) => { + println!("Sub result is: {}", value); + assert(value == 5, 'invalid sub'); + }, + Result::Err(err) => { + println!("subtraction failed: {}", err); + assert(false, 'unexpected error in sub_num'); + }, + } let mul_result: u8 = mul_num(5, 2); println!("Mul result of x & y is {}", mul_result); assert(mul_result == 10, 'invalid mul'); - let div_result = div_num(0, 10); + let div_result = div_num(10, 10); match div_result { Result::Ok(value) => { println!("Div result of x & y is {}", value); @@ -26,64 +33,28 @@ fn main() { assert(false, 'unexpected error in div_num'); }, } - - let input: felt252 = 200; - let mutated = mutate_byte(input); - match mutated { - Result::Ok(value) => { - println!("Mutated byte: {}", value); - assert(value == 199, 'invalid mutate_byte result'); - }, - Result::Err(err) => { - println!("mutation failed: {}", err); - assert(false, 'unexpected error in mutate_byte'); - }, - } } -// addition logic fn add_num(x: u8, y: u8) -> u8 { x + y } -// subtraction logic -fn sub_num(x: u8, y: u8) -> u8 { - if x > y { - x - y +fn sub_num(x: u8, y: u8) -> Result { + if y > x { + Result::Err('result would be negative') } else { - 0 + Result::Ok(x - y) } } -// multiplication logic fn mul_num(x: u8, y: u8) -> u8 { x * y } -// division logic -fn div_num(x:u8, y: u8) -> Result { +fn div_num(x: u8, y: u8) -> Result { if y != 0 { Result::Ok(x / y) } else { Result::Err('not divisible by zero') } -} -// Convert a felt252 input into a u8, returning an error if the value is too large. -fn parse_u8(input: felt252) -> Result { - let input_u256: u256 = input.into(); - if input_u256 < 256 { - Result::Ok(input.try_into().unwrap()) - } else { - Result::Err('Invalid Integer') - } -} - -// Mutate the parsed byte, preserving failure semantics. -fn mutate_byte(input: felt252) -> Result { - let input_to_u8 = match parse_u8(input) { - Result::Ok(num) => num, - Result::Err(err) => { return Result::Err(err); }, - }; - let res = input_to_u8 - 1; - Result::Ok(res) -} +} \ No newline at end of file From eb5badd9753afd9b5ee594b242eb733bd1170d53 Mon Sep 17 00:00:00 2001 From: Chibey-max Date: Wed, 29 Apr 2026 08:37:27 +0100 Subject: [PATCH 3/5] refactor: simplify lib.cairo and extract counter contract - remove parse_u8 and mutate_byte helpers from lib.cairo - remove duplicate function definitions from lib.cairo - remove unused u256 import from lib.cairo - add counter.cairo with ICounter interface and Counter contract - add onlyOwner access control to increase_count and reduce_count - add increase_count delegating addition logic to add_num - add reduce_count delegating subtraction logic to sub_num - add CountIncreased and CountDecreased events --- starknet_contracts/src/counter.cairo | 71 ++++++++++++++++++++++++++++ starknet_contracts/src/lib.cairo | 47 ++++++++---------- 2 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 starknet_contracts/src/counter.cairo diff --git a/starknet_contracts/src/counter.cairo b/starknet_contracts/src/counter.cairo new file mode 100644 index 0000000..a311b02 --- /dev/null +++ b/starknet_contracts/src/counter.cairo @@ -0,0 +1,71 @@ +#[starknet::interface] +trait ICounter { + fn get_count(self: @TContractState) -> u8; + fn increase_count(ref self: TContractState, amount: u8); + fn reduce_count(ref self: TContractState, amount: u8); +} + +#[starknet::contract] +pub mod Counter { + use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use crate::{add_num, sub_num}; + + #[storage] + struct Storage { + owner: starknet::ContractAddress, + count: u8, + } + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + CountIncreased: CountIncreased, + CountDecreased: CountDecreased, + } + + #[derive(Drop, starknet::Event)] + struct CountIncreased { by: u8, new_value: u8 } + + #[derive(Drop, starknet::Event)] + struct CountDecreased { by: u8, new_value: u8 } + + #[constructor] + fn constructor(ref self: ContractState, initial_count: u8) { + self.owner.write(starknet::get_caller_address()); + self.count.write(initial_count); + } + + fn assert_only_owner(self: @ContractState) { + assert( + starknet::get_caller_address() == self.owner.read(), + 'Caller is not the owner' + ); + } + + #[abi(embed_v0)] + impl CounterImpl of super::ICounter { + + fn get_count(self: @ContractState) -> u8 { + self.count.read() + } + + fn increase_count(ref self: ContractState, amount: u8) { + assert_only_owner(@self); + let current = self.count.read(); + let new_value = add_num(current, amount); + self.count.write(new_value); + self.emit(CountIncreased { by: amount, new_value }); + } + + fn reduce_count(ref self: ContractState, amount: u8) { + assert_only_owner(@self); + let current = self.count.read(); + let new_value = match sub_num(current, amount) { + Result::Ok(value) => value, + Result::Err(err) => panic!("{}", err), + }; + self.count.write(new_value); + self.emit(CountDecreased { by: amount, new_value }); + } + } +} \ No newline at end of file diff --git a/starknet_contracts/src/lib.cairo b/starknet_contracts/src/lib.cairo index f1b82bb..00647d8 100644 --- a/starknet_contracts/src/lib.cairo +++ b/starknet_contracts/src/lib.cairo @@ -1,32 +1,27 @@ -/// Interface representing `HelloContract`. -/// This interface allows modification and retrieval of the contract's storage count. -#[starknet::interface] -pub trait ICounter { - /// Increase count. - fn increase_count(ref self: T, amount: u32); - /// Retrieve count. - fn get_count(self: @T) -> u32; -} +pub mod counter; + +use core::result::Result; -/// Simple contract for managing count. -#[starknet::contract] -mod Counter { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; +pub fn add_num(x: u8, y: u8) -> u8 { + x + y +} - #[storage] - struct Storage { - count: u32, +pub fn sub_num(x: u8, y: u8) -> Result { + if y > x { + Result::Err('result would be negative') + } else { + Result::Ok(x - y) } +} - #[abi(embed_v0)] - impl CounterImpl of super::ICounter { - fn increase_count(ref self: ContractState, amount: u32) { - assert(amount != 0, 'Amount cannot be 0'); - self.count.write(self.count.read() + amount); - } +pub fn mul_num(x: u8, y: u8) -> u8 { + x * y +} - fn get_count(self: @ContractState) -> u32 { - self.count.read() - } +pub fn div_num(x: u8, y: u8) -> Result { + if y != 0 { + Result::Ok(x / y) + } else { + Result::Err('not divisible by zero') } -} +} \ No newline at end of file From 86b4174a4f4949b7a2087e47f65e9d35a71f3c96 Mon Sep 17 00:00:00 2001 From: Chibey-max Date: Wed, 29 Apr 2026 09:45:19 +0100 Subject: [PATCH 4/5] feat:updated the constructor and the snfoundry.toml --- starknet_contracts/snfoundry.toml | 4 ++++ starknet_contracts/src/counter.cairo | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/starknet_contracts/snfoundry.toml b/starknet_contracts/snfoundry.toml index c06aab7..5e24ead 100644 --- a/starknet_contracts/snfoundry.toml +++ b/starknet_contracts/snfoundry.toml @@ -1,3 +1,7 @@ +[sncast.dave] +url = "https://starknet-sepolia.public.blastapi.io/rpc/v0_7" +accounts-file = "~/.starknet_accounts/starknet_open_zeppelin_accounts.json" +account = "dave" # Visit https://foundry-rs.github.io/starknet-foundry/appendix/snfoundry-toml.html # and https://foundry-rs.github.io/starknet-foundry/projects/configuration.html for more information diff --git a/starknet_contracts/src/counter.cairo b/starknet_contracts/src/counter.cairo index a311b02..e722020 100644 --- a/starknet_contracts/src/counter.cairo +++ b/starknet_contracts/src/counter.cairo @@ -30,10 +30,10 @@ pub mod Counter { struct CountDecreased { by: u8, new_value: u8 } #[constructor] - fn constructor(ref self: ContractState, initial_count: u8) { - self.owner.write(starknet::get_caller_address()); - self.count.write(initial_count); - } +fn constructor(ref self: ContractState, owner: starknet::ContractAddress, initial_count: u8) { + self.owner.write(owner); + self.count.write(initial_count); +} fn assert_only_owner(self: @ContractState) { assert( From 7ca3bcd8c476a0456d867fe8a46c2e59ff2e849b Mon Sep 17 00:00:00 2001 From: Chibey-max Date: Thu, 21 May 2026 16:45:12 +0100 Subject: [PATCH 5/5] feat:updated the integer contract --- cairo_program/Scarb.toml | 3 ++ cairo_program/src/integer.cairo | 38 ++++++++++++++++-- .../2.18.0_proc_macro.cache | Bin 15413 -> 3 bytes 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cairo_program/Scarb.toml b/cairo_program/Scarb.toml index b6c900a..e9c5e6e 100644 --- a/cairo_program/Scarb.toml +++ b/cairo_program/Scarb.toml @@ -13,4 +13,7 @@ enable-gas = false [dependencies] cairo_execute = "2.18.0" +[dev-dependencies] +cairo_test = "2.17.0" + diff --git a/cairo_program/src/integer.cairo b/cairo_program/src/integer.cairo index abf3435..e0c5361 100644 --- a/cairo_program/src/integer.cairo +++ b/cairo_program/src/integer.cairo @@ -22,11 +22,11 @@ fn main() { println!("Mul result of x & y is {}", mul_result); assert(mul_result == 10, 'invalid mul'); - let div_result = div_num(10, 10); + let div_result = div_num(10, 0); match div_result { Result::Ok(value) => { println!("Div result of x & y is {}", value); - assert(value == 1, 'invalid div'); + assert(value == 1, 'division by zero'); }, Result::Err(err) => { println!("division failed: {}", err); @@ -38,6 +38,38 @@ fn main() { fn add_num(x: u8, y: u8) -> u8 { x + y } +#[cfg(test)] +mod tests { + use core::result::Result; + use super::{add_num, div_num, mul_num, sub_num}; + + #[test] + fn test_add_num() { + let result = add_num(5, 6); + assert(result == 11, 'invalid sum logic'); + } + #[test] + fn test_sub_num() { + let result = sub_num(3, 1); + match result { + Result::Ok(value) => assert(value == 2, 'invalid subtraction logic'), + Result::Err(_) => assert(false, 'unexpected error in sub_num'), + } + } + #[test] + fn test_mul_num() { + let result = mul_num(2, 2); + assert(result == 4, 'invalid multiplication logic'); + } + #[test] + fn test_div_num() { + let result = div_num(6, 2); + match result { + Result::Ok(value) => assert(value == 3, 'invalid division logic'), + Result::Err(_) => assert(false, 'unexpected error in div_num'), + } + } +} fn sub_num(x: u8, y: u8) -> Result { if y > x { @@ -57,4 +89,4 @@ fn div_num(x: u8, y: u8) -> Result { } else { Result::Err('not divisible by zero') } -} \ No newline at end of file +} diff --git a/target/cairo-language-server/2.18.0_proc_macro.cache b/target/cairo-language-server/2.18.0_proc_macro.cache index 9a48e13bcbd69a2d1ebbb364d1124538540e3eb1..4227ca4e8736af63036e7457e2db376ddf7e5795 100644 GIT binary patch literal 3 KcmZQzU;qFB0{{U4 literal 15413 zcmeI236xaTxrO_jb8n2qBx(eiErFKqfPf5*7BmWiI0W#4Od=N5)wiMO>grB)HG|Ng zf)isj2%RvRAd|*KOca8~M2LVHm|_qVG$3dcWCqP2lehmKXs;i+gkj{Sr3v>Nlz_X)LWbxo@_p`5a4dPIw& zcp?b5ZvEdrwp@>&K8t3nqGX6Ijx3f6qUAxPAex9KV?j=CXk4uj{!0YuQ1#1;L< zvs9k;Anvdt1wm11D&PZEFhTPWX z)dzdpL!R|^v~OFz7r!CZj~gvY+gEkkJ^%T^xI5*C+PD432UA(=(_fmey|!`e(1G+b zuj!C@Nm(Kui>D)HsUQ{<2K@2F@GgYIWk{*=AQ=wd?p({vhQ86{@ZiP~L9E!_V83}m zDje<>Pmhk52kzz|77q7_^(k|)th79c7nbtlIp;R?3x<~j$#mCLkc_&UV)0b0BAyP1 zKYOn0@@j7DT3Fbtw6Nx_y($u)-8wv49uD`6mUpX&C(`j`%YI|a(?Ln@(56GmllZKM z2liK!N=6eA`%MkT1hI;Av>*`-{k$)4B=V2%Iy^`Q`1J*aIVBb8P^2)Lj)wb{MU$P2 zf<(G)hqhgEukOM*9F|+gW!_JI`}h#T;Z*SLig*eKpexIk}zA-g#7MaS(}? zMfmhk98V6Hol492ED#R&vH!m#6^*BF!9#|_!I-ijmUbVoeRD>~(<2H~(a{m4oZObp z`{3Y9i$X~F>SmtuUwpJkG?6&{ne3N0^Eu$BU7p6%)qK9sIa_q%p9R0G(NrqGYbq5T zYhO}0oD4?GYsR+d*l_st%{VnAb8f(f+{#es^FGfIpN-;0q3TbyJY5(L%hv*5pLjW+ ziHhRGBdLmHPVTr+Do9tPlAZ9F=g(m7g#JHz2FuFIQnX5uXCPI#F8Kyh_3F`=45aGU zr+fpcMvbVefz*{(Qg;KXX3eOFfmC)j^*4~}(18XRNaf|xKm)0c9chq()V0^ra098H zJ!yo2)Xg{3XalK%18Izb)Sy8$)drf9qJdN-LiZa;6%^1U1F2YyrW;6= zl+X+VsbrF78c3Cv(svA`%F1Y&fz-nf({cl;M;@US22xX|&{GCdQ>W4z1F5-l=|uyn zdGqKc1F8A*=@$l43l`AJ22u+b(mDgF#fxdZfz;Baw821X*)sa0fz0JYLWUq;~D1zZppF-c1*IkUDUHzUo2h;6eJj2dP7c=wc62hY!;w9;A*Op-VkT z9X(3l@E~>U7&Y@Cd=IR$J<5jjt*-LuDugdtHTS4F!Ua|>J!*+?kyV~Yc?fl^I(pO* z;c}~<9`!_MZgsOqHzVX&-RjY;2;a22&7<28T3CI{qi-R!wCd$iFNCYD`g+tCp{-Sa zkNP8Yuo~de0E9fNm`5>$8?6dGDn#gR6?haN^sp-Os0iUEt1^$u5N@~nwnyJa_z$b` z9*sx1%c|0&N`#?S6Fi!LaJSV&k0v5StnT&bUW8#*lRcV@P-r#9qbUd@t)_Z36`|Ow z%A+cTF;?I6=z9obt>$_(7h#;$JdfrfjJI0g(E@}CRtr5^h%nJ=kw=RV?zMW>qh}Ew zwOZ-XN`%L(p7ZEAgzvJll=^Gd-J4flptLi(wllTsI8&#-GxZxd)1aX<4VyXBEZdpv ztDL#2l{2kcJJY(IGws?t)4qc<9jM&h+l%OrHVH z3>fIlz#+~IxyzZmhB`Ae;!I?iGsB|JL<47nB4>(5Iy17^nc{>qiL^863TG-tIWua4 zGZQ8{GjWnLlO{Ve`2lAhc+{CkA9Loh+0M+KgfTHOVrYo8uVTPia5@sq|C}E+ZMG_V%dP2ezihdyB z2a1+SSf*&Xgyo7>NLZohDG5(0dRoHMihd&DCyJhx@T{Vh5>_huxrCo9S|eeNq8BB+ zsOa|+ey?bggiVSzOW3Svi-awTUYGE?qCZObqoVB+wkz5tVV9!a5_T(kTf*ClK9cZ} zqC*l6DLO3Su%eR^PAWPj;glkhK#Kk<;jfB5mGG&etm?}G9LY5Tj_%mTS~p{b^35}IksmXNKfg@hKGT1sfC>1qjA zYw9eav!;9r`I@>&=%T5+gzlPpNa&&I774d#x>drhnr@SDo2K3pdTZ(4mnx2vHjHVw; z__3yy5>{$@PQr7VUXt*Vre8?-g{GG!ysYUJ39o2cD`BmsbrRNT`n7~#YuYGbqo&s+ zyr$_l5`Lp;vxLo>wn*5bX{&^-n%7ayznm&^7ktSoRuM5VO#>{$=8zhQj-Fn<0Q5@^l z=LUHJ8e{|fOJ9~dec4bg3AGG;MZ#AM)saxg(B%>?H&jWwBqazT#wO;JLGXa9*BC}k?Zjw)Z=Tp9-|ds+mq`tT5->txgL*3Js!yQcns?C zAg;$~#e)WOJw_`Yd?(jqwBkD>T#wO;BL!TK(TWRVT#wO;VN4OrN6+beC>oHpKl&M^g(Tb{n#@e5p!-#|TH#q}7i zc-3mI$7sc?*K$2ZD_*;f>oHpKx=mb<(TX>1=6Z})ym<@PW3=KeTe%*i6>r_f_4pL( z@pi7qXvN!iaXm&W-nEyF zEk;4+P7H@yjDpOa7%or2*-i|HT8x6sofxh=mY$hT42N2bg3O&54z(BsnL9BYYB35j zcValyViaWV#Bg_^hh{o4+)ykdGo2U?>s=IN?!;g%yeQn z)M6B5?!<6d{GuRpCx$~UMnUFI42N2bg3O&54z(BsnL9Ducm-!WF&x&eD9GH2;jnf^ zLFP^jhgyt+%$*qSQLF+pofrzH0^2j{_rgIqaRQx-qSTzpj ztWj1!9Bg-)NrnEaJtF zsz)k?Q6}G?r!V$FGjm4XiT`txyKjEBQ>$n?2ZxoPA8OvUq_iT5d8GaHLj^&oP4kwa zvvzfF6F*v|Jpc?6PoJqR@z2lHss~!1J5xKyU)cFk+c^&I{?$?2Ierc}H~bqWa9@1# zmHFH`9@GE!*sjLO?))j+ULF7MoU-i@v7tssP0MfD7%l%o0uQUF3%8c1DuA*vg< zw_3GO!MKGrXn^{~4Xj~9R4;B{7&M{^p%eA$chzJH3O;f{4RpB&sf`=CKcGzP*g-iSq;~G4Tn|!jzDeKoAobQ; z)WU;!_}9jR)Sf-m&V$sxebnBA)c*a{&4bkO<8-43sS_uty9cS0C#i=AsZ*!u4iBoH z?72}IiVHN%gA`qA74;~J@C~a1j|vbjvvNbW+KQmK2Qf!yjr1Tz4XuhjDn@8zmGCHm z(AcWPqY{KGtWYSpT{N{C?a^q2T&po2jX^*Sf*$lBMb}zAxrp`XI08HK$vIsp+_Gg%(pt^(IEuzd+3MYsN`w*jZRtq0ubk4fk zhnSYL+V~J&z11~7U4yXKs*_Kh5Dr>(_Ng<%M^^bhzaP(LjWRp*TJQI2tWkyx;{Vh#<>6d$Qy6M`H?sO*KNo*Uu9YPShA*`!baB z`C?lAXt=CiAOV-vuS)o8jk)xtvIW=JZ%Dv3_A&{V@x`?Ip>bKQD*>0)dJ=G1&6bd@ z=_(0VX=*N^xuzTmIhxu_Xs@Y*gbteWB;;udO9*S~B%xD{@pU)Zg3IcS5^z~PV|?9D zw)Eo*WA%%}C9=N+Tq1`^7^3Me33q+bkh(y2D>&zg^=P@zXiZ}zjL|e+!uT(mSf4SM zzF+QhzotnNCSd^~VV0)HB|NTawuIT5=17>MsY*iCInT1s80v152iT_R4-)>M>2(RO zYkEV%8=7`V*zrYE;df-WcQpM;!k=o)aSzCr12u-ahh@uQO-Cdg(R5V8QBB7r9Mg14 z!YNH3OZZsRClWr<^fw8A)AV-h~8CoD=fuV&G7FvGejtwve45#k^hB;t30|qn90mH$78!!h9=gyG~bHH#$7BkEN z!zoTM%)wwfQNl0>45wr~!yGW2@s$j7z;G(3G0XwOnKqqa4j9h#84Pp4aAwS8m;;70 za~8uKFq~O)80LWC%&B6S1BO$zlwl4S4u;o&Ibb-;mNU!&!&$z9VGbD1idPxtfZ@El zo?#9c&iV}ubHH#mY-E@NhO==8!yGW29XlE3fZ^fV0mC`P(`Vou9{j?A z-~i_^!GXKf;v6P8aDX_#IZSZiE>m!JBn$_F1DwMI2Mz=WIEM)i93T#GPB8);7Kg z2Z95f!vqKJhZg5B!GZgk0?V-k2M$YG;2b76aDX_#IZSZieuuA9hTy<~-~i_^!GQz8 z0nTB90|$ZwoWleMZkNS5OmN`dwm63g4%{A#bC}@3?FFgG5FEIJ`1)iB4%|oh`eX_U}s4ilXIOmG